Merge branch 'master' into ab-fetch-token-counters-in-parallel

pull/2666/head
Victor Baranov 5 years ago committed by GitHub
commit f12e61e865
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      CHANGELOG.md
  2. 4
      apps/block_scout_web/assets/close.svg
  3. 1
      apps/block_scout_web/assets/css/_images-preload.scss
  4. 7
      apps/block_scout_web/assets/css/components/_card.scss
  5. 2
      apps/block_scout_web/assets/css/components/_dashboard-banner.scss
  6. 2
      apps/block_scout_web/assets/css/components/_dropdown.scss
  7. 140
      apps/block_scout_web/assets/css/components/_navbar.scss
  8. 3
      apps/block_scout_web/assets/css/components/_network-selector.scss
  9. 12
      apps/block_scout_web/assets/css/components/_tile.scss
  10. 58
      apps/block_scout_web/assets/css/theme/_dai_variables.scss
  11. 45
      apps/block_scout_web/assets/css/theme/_dark-theme.scss
  12. 1
      apps/block_scout_web/assets/css/theme/_variables-non-critical.scss
  13. 1
      apps/block_scout_web/assets/css/theme/_variables.scss
  14. 7
      apps/block_scout_web/assets/css/theme/_xusdt_variables-non-critical.scss
  15. 97
      apps/block_scout_web/assets/css/theme/_xusdt_variables.scss
  16. 9
      apps/block_scout_web/assets/js/pages/dark-mode-switcher.js
  17. 37
      apps/block_scout_web/assets/js/pages/layout.js
  18. 14
      apps/block_scout_web/assets/static/images/dai_logo.svg
  19. 4
      apps/block_scout_web/assets/static/images/network-selector-icons/circle-xusdt.svg
  20. 4
      apps/block_scout_web/assets/static/images/network-selector-icons/xdai-chain.svg
  21. 3
      apps/block_scout_web/assets/static/images/xusdt-logo-footer.svg
  22. 4
      apps/block_scout_web/assets/static/images/xusdt-logo-top.svg
  23. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
  24. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
  25. 28
      apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
  26. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_decompiled_contract_controller.ex
  27. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_internal_transaction_controller.ex
  28. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex
  29. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
  30. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_controller.ex
  31. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex
  32. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  33. 8
      apps/block_scout_web/lib/block_scout_web/controllers/address_validation_controller.ex
  34. 12
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  35. 2
      apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
  36. 49
      apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
  37. 48
      apps/block_scout_web/lib/block_scout_web/templates/common_components/_tile-loader.html.eex
  38. 32
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  39. 2
      apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex
  40. 9
      apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
  41. 43
      apps/block_scout_web/priv/gettext/default.pot
  42. 43
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  43. 20
      apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
  44. 47
      apps/block_scout_web/test/block_scout_web/views/address_contract_view_test.exs
  45. 4
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/receipts.ex
  46. 23
      apps/explorer/config/config.exs
  47. 4
      apps/explorer/lib/explorer/application.ex
  48. 22
      apps/explorer/lib/explorer/chain.ex
  49. 4
      apps/explorer/lib/explorer/chain/cache/block_count.ex
  50. 4
      apps/explorer/lib/explorer/chain/cache/block_number.ex
  51. 4
      apps/explorer/lib/explorer/chain/cache/blocks.ex
  52. 4
      apps/explorer/lib/explorer/chain/cache/transaction_count.ex
  53. 4
      apps/explorer/lib/explorer/chain/cache/transactions.ex
  54. 163
      apps/explorer/lib/explorer/chain/import/runner/blocks.ex
  55. 42
      apps/explorer/lib/explorer/chain/ordered_cache.ex
  56. 39
      apps/explorer/lib/explorer/chain/smart_contract.ex
  57. 46
      apps/explorer/lib/explorer/chain_spec/parity/importer.ex
  58. 89
      apps/explorer/lib/explorer/chain_spec/poa/importer.ex
  59. 32
      apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex
  60. 7
      apps/explorer/priv/repo/migrations/20190910170703_create_indexes_for_block_number_in_token_transfers_and_transactions.exs
  61. 6
      apps/explorer/test/explorer/chain/cache/block_number_test.exs
  62. 114
      apps/explorer/test/explorer/chain/import/runner/blocks_test.exs
  63. 101
      apps/explorer/test/explorer/exchange_rates/source/coin_gecko_test.exs
  64. 14
      apps/indexer/test/indexer/block/fetcher/receipts_test.exs
  65. 9
      docs/env-variables.md

@ -1,9 +1,32 @@
## Current ## Current
### Features ### Features
- [#2679](https://github.com/poanetwork/blockscout/pull/2679) - added fixed height for card chain blocks and card chain transactions
- [#2678](https://github.com/poanetwork/blockscout/pull/2678) - fixed dashboard banner height bug
- [#2672](https://github.com/poanetwork/blockscout/pull/2672) - added new theme for xUSDT
- [#2666](https://github.com/poanetwork/blockscout/pull/2666) - fetch token counters in parallel - [#2666](https://github.com/poanetwork/blockscout/pull/2666) - fetch token counters in parallel
- [#2665](https://github.com/poanetwork/blockscout/pull/2665) - new menu layout for mobile devices
- [#2663](https://github.com/poanetwork/blockscout/pull/2663) - Fetch address counters in parallel
### Fixes
- [#2701](https://github.com/poanetwork/blockscout/pull/2701) - Exclude nonconsensus blocks from avg block time calculation by default
- [#2693](https://github.com/poanetwork/blockscout/pull/2693) - remove non consensus internal transactions
- [#2687](https://github.com/poanetwork/blockscout/pull/2687) - remove non-consensus token transfers, logs when inserting new consensus blocks
- [#2684](https://github.com/poanetwork/blockscout/pull/2684) - do not filter pending logs
- [#2682](https://github.com/poanetwork/blockscout/pull/2682) - Use Task.start instead of Task.async in caches
- [#2671](https://github.com/poanetwork/blockscout/pull/2671) - fixed buttons color at smart contract section
- [#2691](https://github.com/poanetwork/blockscout/pull/2691) - fix exchange rate websocket update for Rootstock
### Chore
## 2.0.4-beta
### Features
- [#2636](https://github.com/poanetwork/blockscout/pull/2636) - Execute all address' transactions page queries in parallel - [#2636](https://github.com/poanetwork/blockscout/pull/2636) - Execute all address' transactions page queries in parallel
- [#2596](https://github.com/poanetwork/blockscout/pull/2596) - support AuRa's empty step reward type - [#2596](https://github.com/poanetwork/blockscout/pull/2596) - support AuRa's empty step reward type
- [#2588](https://github.com/poanetwork/blockscout/pull/2588) - add verification submission comment
- [#2505](https://github.com/poanetwork/blockscout/pull/2505) - support POA Network emission rewards
- [#2581](https://github.com/poanetwork/blockscout/pull/2581) - Add generic Map-like Cache behaviour and implementation - [#2581](https://github.com/poanetwork/blockscout/pull/2581) - Add generic Map-like Cache behaviour and implementation
- [#2561](https://github.com/poanetwork/blockscout/pull/2561) - Add token's type to the response of tokenlist method - [#2561](https://github.com/poanetwork/blockscout/pull/2561) - Add token's type to the response of tokenlist method
- [#2555](https://github.com/poanetwork/blockscout/pull/2555) - find and show decoding candidates for logs - [#2555](https://github.com/poanetwork/blockscout/pull/2555) - find and show decoding candidates for logs
@ -12,14 +35,14 @@
### Fixes ### Fixes
- [#2659](https://github.com/poanetwork/blockscout/pull/2659) - Multipurpose front-end part update - [#2659](https://github.com/poanetwork/blockscout/pull/2659) - Multipurpose front-end part update
- [#2468](https://github.com/poanetwork/blockscout/pull/2468) - fix confirmations for non consensus blocks
- [#2610](https://github.com/poanetwork/blockscout/pull/2610) - use CoinGecko instead of CoinMarketcap for exchange rates
- [#2640](https://github.com/poanetwork/blockscout/pull/2640) - SVG network icons - [#2640](https://github.com/poanetwork/blockscout/pull/2640) - SVG network icons
- [#2635](https://github.com/poanetwork/blockscout/pull/2635) - optimize ERC721 inventory query - [#2635](https://github.com/poanetwork/blockscout/pull/2635) - optimize ERC721 inventory query
- [#2626](https://github.com/poanetwork/blockscout/pull/2626) - Fixing 2 Mobile UI Issues - [#2626](https://github.com/poanetwork/blockscout/pull/2626) - Fixing 2 Mobile UI Issues
- [#2623](https://github.com/poanetwork/blockscout/pull/2623) - fix a blinking test - [#2623](https://github.com/poanetwork/blockscout/pull/2623) - fix a blinking test
- [#2616](https://github.com/poanetwork/blockscout/pull/2616) - deduplicate coin history records by delta - [#2616](https://github.com/poanetwork/blockscout/pull/2616) - deduplicate coin history records by delta
- [#2613](https://github.com/poanetwork/blockscout/pull/2613) - fix getminedblocks rpc endpoint - [#2613](https://github.com/poanetwork/blockscout/pull/2613) - fix getminedblocks rpc endpoint
- [#2612](https://github.com/poanetwork/blockscout/pull/2612) - Add cache updating independently from Indexer
- [#2610](https://github.com/poanetwork/blockscout/pull/2610) - use CoinGecko instead of CoinMarketcap for exchange rates
- [#2592](https://github.com/poanetwork/blockscout/pull/2592) - process new metadata format for whisper - [#2592](https://github.com/poanetwork/blockscout/pull/2592) - process new metadata format for whisper
- [#2591](https://github.com/poanetwork/blockscout/pull/2591) - Fix url error in API page - [#2591](https://github.com/poanetwork/blockscout/pull/2591) - Fix url error in API page
- [#2572](https://github.com/poanetwork/blockscout/pull/2572) - Ease non-critical css - [#2572](https://github.com/poanetwork/blockscout/pull/2572) - Ease non-critical css
@ -29,8 +52,10 @@
- [#2564](https://github.com/poanetwork/blockscout/pull/2564) - fix first page button for uncles and reorgs - [#2564](https://github.com/poanetwork/blockscout/pull/2564) - fix first page button for uncles and reorgs
- [#2563](https://github.com/poanetwork/blockscout/pull/2563) - Fix view less transfers button - [#2563](https://github.com/poanetwork/blockscout/pull/2563) - Fix view less transfers button
- [#2538](https://github.com/poanetwork/blockscout/pull/2538) - fetch the last not empty coin balance records - [#2538](https://github.com/poanetwork/blockscout/pull/2538) - fetch the last not empty coin balance records
- [#2468](https://github.com/poanetwork/blockscout/pull/2468) - fix confirmations for non consensus blocks
### Chore ### Chore
- [#2662](https://github.com/poanetwork/blockscout/pull/2662) - fetch coin gecko id based on the coin symbol
- [#2646](https://github.com/poanetwork/blockscout/pull/2646) - Added Xerom to list of Additional Chains using BlockScout - [#2646](https://github.com/poanetwork/blockscout/pull/2646) - Added Xerom to list of Additional Chains using BlockScout
- [#2634](https://github.com/poanetwork/blockscout/pull/2634) - add Lukso to networks dropdown - [#2634](https://github.com/poanetwork/blockscout/pull/2634) - add Lukso to networks dropdown
- [#2617](https://github.com/poanetwork/blockscout/pull/2617) - skip cache update if there are no blocks inserted - [#2617](https://github.com/poanetwork/blockscout/pull/2617) - skip cache update if there are no blocks inserted

@ -0,0 +1,4 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 47.971 47.971" style="enable-background:new 0 0 47.971 47.971;" xml:space="preserve"><g><g>
<path d="M28.228,23.986L47.092,5.122c1.172-1.171,1.172-3.071,0-4.242c-1.172-1.172-3.07-1.172-4.242,0L23.986,19.744L5.121,0.88 c-1.172-1.172-3.07-1.172-4.242,0c-1.172,1.171-1.172,3.071,0,4.242l18.865,18.864L0.879,42.85c-1.172,1.171-1.172,3.071,0,4.242 C1.465,47.677,2.233,47.97,3,47.97s1.535-0.293,2.121-0.879l18.865-18.864L42.85,47.091c0.586,0.586,1.354,0.879,2.121,0.879 s1.535-0.293,2.121-0.879c1.172-1.171,1.172-3.071,0-4.242L28.228,23.986z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#828BA0"/>
</g></g> </svg>

After

Width:  |  Height:  |  Size: 806 B

@ -13,4 +13,5 @@ body:after {
url(/images/network-selector-icons/ropsten-testnet.svg) url(/images/network-selector-icons/ropsten-testnet.svg)
url(/images/network-selector-icons/xdai-chain.svg) url(/images/network-selector-icons/xdai-chain.svg)
url(/images/network-selector-icons/lukso-l14-testnet.svg) url(/images/network-selector-icons/lukso-l14-testnet.svg)
url(/images/network-selector-icons/circle-xusdt.svg)
}; };

@ -155,8 +155,8 @@ $card-tab-icon-color-active: #fff !default;
} }
.card-chain-blocks { .card-chain-blocks {
height: auto; min-height: 233px;
max-height: auto;
[class*="col-"]:last-child { [class*="col-"]:last-child {
.tile { .tile {
margin-bottom: 0; margin-bottom: 0;
@ -165,7 +165,8 @@ $card-tab-icon-color-active: #fff !default;
} }
.card-chain-transactions { .card-chain-transactions {
height: auto; min-height: 664px;
max-height: auto;
.tile { .tile {
margin-bottom: 0; margin-bottom: 0;

@ -148,7 +148,7 @@ $dashboard-banner-chart-axis-font-color: $dashboard-stats-item-value-color !defa
display: flex; display: flex;
height: $dashboard-banner-network-plain-container-height; height: $dashboard-banner-network-plain-container-height;
justify-content: center; justify-content: center;
margin: 0 0 0 30px; margin: 45px 0 0 30px;
max-width: 100%; max-width: 100%;
padding: 30px 0 30px 60px; padding: 30px 0 30px 60px;
width: 750px; width: 750px;

@ -1,6 +1,6 @@
$dropdown-menu-item-color: #333 !default; $dropdown-menu-item-color: #333 !default;
$dropdown-menu-item-hover-color: $secondary !default; $dropdown-menu-item-hover-color: $secondary !default;
$dropdown-menu-item-hover-background: rgba($secondary, .1) !default; $dropdown-menu-item-hover-background: rgba($secondary, 0.1) !default;
// These styles extend the default Bootstrap styles // These styles extend the default Bootstrap styles
.dropdown-menu { .dropdown-menu {

@ -92,7 +92,7 @@ $navbar-logo-width: auto !default;
} }
.navbar-toggler { .navbar-toggler {
border-color: $primary; outline: none;
color: $primary; color: $primary;
.navbar-toggler-icon { .navbar-toggler-icon {
@ -224,7 +224,7 @@ $navbar-logo-width: auto !default;
} }
.navbar-logo { .navbar-logo {
max-height: $navbar-logo-height; height: $navbar-logo-height;
width: $navbar-logo-width; width: $navbar-logo-width;
} }
@ -259,3 +259,139 @@ $navbar-logo-width: auto !default;
transition: none !important; transition: none !important;
} }
} }
.nav-link-new {
margin-left: auto;
font-size: 14px;
color: #333333;
@include media-breakpoint-up(lg) {
display: none;
}
}
.new-button {
margin-right: -7px !important;
padding-right: 0px;
height: 20px!important;
border-left: 1px solid #a3a9b5!important;
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
background: transparent;
border: none;
cursor: pointer;
outline: none !important;
box-shadow: none !important;
transition: .2s ease-in;
@include media-breakpoint-up(lg) {
display: none!important;
}
}
@media (max-width: 992px) {
.navbar.navbar-primary .navbar-nav .nav-link .nav-link-icon {
display: none;
}
.navbar-nav .nav-item .dropdown-toggle::after {
display: none;
}
.navbar.navbar-primary .navbar-nav .nav-link {
font-size: 28px;
color: #333333;
padding: 0.7rem 1.4rem;
font-weight: 600;
}
.navbar .dropdown-menu {
box-shadow: none;
}
.navbar .dropdown-menu .dark-mode-changer {
display: none;
}
.nav-item .dropdown {
padding: 0px 15%;
font-weight: 600;
}
.last-child {
display: none!important;
}
.search-form {
width: 100%!important;
}
.awesomplete {
height: 50px;
}
.navbar.navbar-primary .input-group-append {
left: 15px !important;
}
.navbar.navbar-primary .form-control {
padding-right: 30px;
padding-left: 13.5%;
}
.dropdown-item {
padding: 10px 1.6rem !important;
color: rgba(51, 51, 51, 0.7)!important;
}
.navbar.navbar-primary .navbar-nav .nav-link:hover,
.navbar.navbar-primary .navbar-nav .nav-link.activeLink,
.navbar.navbar-primary .navbar-nav .nav-link:focus {
background-image: linear-gradient(to right, #f5f6fa, rgba(245, 246, 250, 0));
width: 100%;
}
.navbar.navbar-primary .navbar-nav .nav-link:hover:before {
content: "|";
height: 50px;
width: 50%;
opacity: 1;
background: none;
left: 24%;
top: 14%;
color: $primary;
}
.navbar {
padding: 0.5rem 0rem!important;
}
.navbar-brand {
margin-right: 0px!important;
margin-left: 1rem;
}
.dropdown-item.active,
.dropdown-item:hover,
.dropdown-item:focus {
background-image: linear-gradient(to right, #f5f6fa, rgba(245, 246, 250, 0));
width: 100%;
background-color: white!important;
}
.dropdown-item:hover:before {
content: "|";
height: 50px;
width: 50%;
opacity: 1;
background: none;
right: 17%;
color: $primary;
position: relative;
}
.dark-mode-changer svg path {
fill: #a3a9b5!important;
}
.dropdown-toggle::after {
margin-left: 0.51em!important;
color: #a3a9b5;
}
#toggleImage2 {
display: none;
outline: none;
padding-left: 5px;
padding-right: 5px;
}
#toggleImage1 {
width: 27px!important;
}
.dark-mode-changer {
display: none!important;
}
}

@ -280,6 +280,9 @@ $network-selector-item-icon-dimensions: 30px !default;
&-lukso-l14-testnet { &-lukso-l14-testnet {
background-image: url(/images/network-selector-icons/lukso-l14-testnet.svg) background-image: url(/images/network-selector-icons/lukso-l14-testnet.svg)
} }
&-xusdt-chain {
background-image: url(/images/network-selector-icons/circle-xusdt.svg)
}
} }
.network-selector-item-title { .network-selector-item-title {

@ -562,3 +562,15 @@ $cube-quantity: 5;
transform: scale(0); transform: scale(0);
} }
} }
.dark-block-loader {
width: auto;
height: 15px;
background-color: #e2e5ec;
margin-bottom: 5px;
border-radius: 4px;
}
.dark-theme-applied .dark-block-loader {
background-color: #313355;
}

@ -1,23 +1,23 @@
// general // general
$primary: #17314f; $primary: #233174;
$secondary: #15bba6; $secondary: #15f9bb;
$tertiary: #93d7ff; $tertiary: #5a77ff;
$additional-font: #fff; $additional-font: #fff;
// footer // footer
$footer-background-color: $primary; $footer-background-color:#202d6a;
$footer-title-color: #fff; $footer-title-color: #fff;
$footer-text-color: #96bde8; $footer-text-color: #b5c2ff;
$footer-item-disc-color: $secondary; $footer-item-disc-color: $secondary;
.footer-logo { filter: brightness(0) invert(1); } .footer-logo { filter: brightness(0) invert(1); }
.footer-social-icon { color: $secondary!important; }
// dashboard // dashboard
$dashboard-line-color-price: $tertiary; // price left border $dashboard-line-color-price: $tertiary; // price left border
$dashboard-line-color-market: $secondary; $dashboard-line-color-market: $secondary;
$dashboard-banner-chart-legend-label-color: $footer-text-color; $dashboard-banner-chart-legend-label-color: $footer-text-color;
$dashboard-stats-item-label-color: $footer-text-color; $dashboard-stats-item-label-color: #b4c1ff;
$dashboard-banner-chart-legend-value-color: #fff; // chart labels $dashboard-banner-chart-legend-value-color: #fff; // chart labels
$dashboard-stats-item-value-color: #fff; // stat values $dashboard-stats-item-value-color: #fff; // stat values
@ -25,9 +25,11 @@ $dashboard-stats-item-border-color: $secondary; // stat border
$dashboard-banner-gradient-start: $primary; // gradient begin $dashboard-banner-gradient-start: $primary; // gradient begin
$dashboard-banner-gradient-end: lighten($primary, 5); // gradient end $dashboard-banner-gradient-end: #1e2a63;
// gradient end
$dashboard-banner-network-plain-container-background-color: #20446e; // stats bg $dashboard-banner-network-plain-container-background-color: #273781
; // stats bg
// navigation // navigation
@ -35,20 +37,20 @@ $dashboard-banner-network-plain-container-background-color: #20446e; // stats bg
// buttons // buttons
$btn-line-bg: #fff; // button bg $btn-line-bg: #fff; // button bg
$btn-line-color: $secondary; // button border and font color && hover bg color $btn-line-color: $primary; // button border and font color && hover bg color
$btn-copy-color: $secondary; // btn copy $btn-copy-color: $primary; // btn copy
$btn-qr-color: $secondary; // btn qr-code $btn-qr-color: $primary; // btn qr-code
$btn-address-card-icon-color: $secondary; // btn address color $btn-address-card-icon-color: $secondary; // btn address color
//links & tile //links & tile
$tile-body-a-color: $secondary; $tile-body-a-color: $tertiary;
$tile-type-block-color: $secondary; $tile-type-block-color: $primary;
$tile-type-progress-bar-color: $secondary; $tile-type-progress-bar-color: $primary;
a.tile-title { color: $secondary !important; } a.tile-title { color: $primary !important; }
// card // card
$card-background-1: $secondary; $card-background-1: $primary;
$card-tab-active: $secondary; $card-tab-active: $primary;
.layout-container { .layout-container {
.dashboard-banner-container { .dashboard-banner-container {
@ -66,6 +68,20 @@ $badge-neutral-background-color: rgba(#20446e, .1);
$api-text-monospace-color: #20446e; $api-text-monospace-color: #20446e;
// Dark theme // Dark theme
$dark-primary: #15bba6; $dark-primary: #233174;
$dark-secondary: #93d7ff; $dark-secondary:#15f9bb;
$dark-primary-alternate: #15bba6; $dark-tertiary: #5a77ff;
.dark-theme-applied .tile .tile-body a, .dark-theme-applied .tile span[data-address-hash] {
color: $dark-tertiary!important;
}
.dark-theme-applied .btn-line {
background-color: transparent!important;
border-color: $dark-tertiary!important;
color: $dark-tertiary!important;
}
.dark-theme-applied .btn-line:hover {
color: $additional-font!important;
}

@ -779,3 +779,48 @@ $labels-dark: #8a8dba; // header nav, labels
} }
} }
} }
.navbar-dark .navbar-toggler {
color: rgba(255, 255, 255, 0.5);
border: none;
}
.dark-theme-applied .dropdown-item {
color: #fff!important;
}
.dark-theme-applied .dropdown-item.active, .dark-theme-applied .dropdown-item:hover, .dark-theme-applied .dropdown-item:focus {
background-image: none;
width: 100%;
background-color: #35335d!important;
}
.dark-theme-applied .dropdown-item:hover:before {
content: "|";
height: 50px;
width: 50%;
opacity: 1;
background: none;
right: 17%;
color: $dark-primary;
position: relative;
}
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:hover,
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link.activeLink,
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:focus {
background-image: none;
width: 100%;
background-color: #35335d!important;
color: white;
border: none;
}
.dark-theme-applied .navbar.navbar-primary .navbar-nav .nav-link:hover:before
{
content: "|";
height: 50px;
width: 50%;
opacity: 1;
background: none;
left: 24%;
top: 14%;
color: $dark-primary;
}

@ -1,5 +1,6 @@
@import "theme/base_variables"; @import "theme/base_variables";
@import "neutral_variables-non-critical"; @import "neutral_variables-non-critical";
// @import "xusdt_variables-non-critical";
// @import "dai_variables-non-critical"; // @import "dai_variables-non-critical";
// @import "ethereum_classic_variables-non-critical"; // @import "ethereum_classic_variables-non-critical";
// @import "ethereum_variables-non-critical"; // @import "ethereum_variables-non-critical";

@ -1,5 +1,6 @@
@import "theme/base_variables"; @import "theme/base_variables";
@import "neutral_variables"; @import "neutral_variables";
// @import "xusdt_variables";
// @import "dai_variables"; // @import "dai_variables";
// @import "ethereum_classic_variables"; // @import "ethereum_classic_variables";
// @import "ethereum_variables"; // @import "ethereum_variables";

@ -0,0 +1,7 @@
// general
$primary: #2b9f7a;
$secondary: #20745a;
$tertiary: #fff;
$additional-font: #fff;
$btn-line-color: $secondary; // button border and font color && hover bg color

@ -0,0 +1,97 @@
// general
$primary: #2b9f7a;
$secondary: #20745a;
$tertiary: #fff;
$additional-font: #fff;
$tile-body-a-color: $primary;
$tile-type-block-color: $primary;
$tile-type-progress-bar-color: $primary;
a.tile-title { color: $primary !important; }
// footer
$footer-background-color: #282d31;
$footer-title-color: #fff;
$footer-text-color: $additional-font;
$footer-item-disc-color: $secondary;
$footer-social-icon-color: $secondary;
// dashboard
$dashboard-line-color-price: #fff; // price left border
$dashboard-banner-chart-legend-label-color: #fff;
$dashboard-stats-item-label-color: $dashboard-banner-chart-legend-label-color;
$dashboard-banner-chart-legend-value-color: #fff; // chart labels
$dashboard-stats-item-value-color: #fff; // stat values
$dashboard-stats-item-border-color: $secondary; // stat border
$dashboard-banner-gradient-start: $primary; // gradient begin
$dashboard-banner-gradient-end: #289371; // gradient end
$dashboard-banner-network-plain-container-background-color: #2ea780; // stats bg
// navigation
.navbar { box-shadow: 0px 0px 30px 0px rgba(21, 53, 80, 0.12); } // header shadow
$dropdown-menu-item-hover-color: $primary !default;
$dropdown-menu-item-hover-background: rgba($primary, .1) !default;
$header-icon-color-hover: $primary;
$header-icon-border-color-hover: $primary;
// buttons
$btn-line-bg: #fff; // button bg
$btn-line-color: $primary; // button border and font color && hover bg color
$btn-copy-color: $primary; // btn copy
$btn-qr-color: $primary; // btn qr-code
$btn-address-card-icon-color: $primary; // btn address color
//links & tile
$tile-body-a-color: $primary;
$tile-type-block-color: $primary;
$tile-type-progress-bar-color: $primary;
a.tile-title { color: $primary !important; }
// card
$card-background-1: $primary;
$card-tab-active: $primary;
.layout-container {
.dashboard-banner-container {
background-image: linear-gradient(
to bottom,
$dashboard-banner-gradient-start,
$dashboard-banner-gradient-end
);
}
}
// Badges
$badge-neutral-color: $primary;
$badge-neutral-background-color: rgba($primary, .1);
$api-text-monospace-color: $primary;
// Tokens dropdown
.token-balance-dropdown[aria-labelledby="dropdown-tokens"] {
.dropdown-items .dropdown-item:hover {
color: $primary !important;
}
}
// Dark theme
$dark-primary: #2b9f7a;
$dark-secondary: #20745a;
$dark-primary-alternate: #2b9f7a;
.dark-theme-applied .dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(1)::before {
background-color: white!important;
}
.dark-theme-applied .dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(2)::before {
background-color: $primary!important;
}
.dark-theme-applied .tile .tile-body a, .dark-theme-applied .tile span[data-address-hash] {
color: #2b9f7a;
}

@ -9,3 +9,12 @@ $('.dark-mode-changer').click(function () {
// reload each theme switch // reload each theme switch
document.location.reload(true) document.location.reload(true)
}) })
$('.new-button').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)
})

@ -7,3 +7,40 @@ $(document).click(function (event) {
$('.navbar-toggler').click() $('.navbar-toggler').click()
} }
}) })
$(document).ready(function () {
if (matchMedia) {
var mq = window.matchMedia('(max-width: 900px)')
mq.addListener(WidthChange)
WidthChange(mq)
}
function WidthChange (mq) {
if (mq.matches) {
$('#checkIfSmall').removeClass('dropdown-menu')
$('.dropdown-item').removeClass('active')
$('#checkIfSmall1').removeClass('dropdown-menu')
$('#checkIfSmall2').removeClass('dropdown-menu')
} else {
$('#checkIfSmall').addClass('dropdown-menu')
$('#checkIfSmall1').addClass('dropdown-menu')
$('#checkIfSmall2').addClass('dropdown-menu')
}
}
})
var div1 = document.getElementById('toggleImage1')
var div2 = document.getElementById('toggleImage2')
function switchVisible () {
if (!div1) return
if (getComputedStyle(div1).display === 'inline-block') {
div1.style.display = 'none'
div2.style.display = 'block'
} else {
div1.style.display = 'inline-block'
div2.style.display = 'none'
}
}
document
.getElementById('toggleButton')
.addEventListener('click', switchVisible)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
<path fill="#12AC97" fill-rule="evenodd" d="M0 30V0h30v30H0z"/>
<path fill="#FFF" fill-rule="evenodd" d="M17.172 15L23 22.001h-4.344.775c-.497 0-.926-.229-1.223-.569l-.015.012-2.654-3.187h-.011a.7.7 0 0 0-.528-.243.7.7 0 0 0-.528.243h-.012l-2.653 3.187-.015-.012c-.297.34-.726.569-1.223.569h.774-4.344L12.828 15 6.999 8h3.569l.001-.001c.497 0 .926.229 1.223.569l.014-.012 2.652 3.185h.012c.13.147.315.245.53.245.215 0 .4-.098.53-.245h.011l2.652-3.185.015.012A1.618 1.618 0 0 1 19.432 8h3.569l-5.829 7z"/>
</svg>

After

Width:  |  Height:  |  Size: 584 B

@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30"> <svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
<path fill="#12AC97" fill-rule="evenodd" d="M30 14.999V30H0V0h30v14.999z"/> <path fill="#202D6A" fill-rule="evenodd" d="M0 30V0h30v30H0z"/>
<path fill="#FFF" fill-rule="evenodd" d="M17.172 14.999l5.828 7h-4.344v-.001h.775c-.497 0-.926-.228-1.223-.568l-.015.012-2.655-3.188h-.019a.681.681 0 0 0-.519-.246.681.681 0 0 0-.519.246h-.019l-2.655 3.188-.015-.012c-.297.34-.726.568-1.223.568h.775v.001H7l5.828-7-5.828-7h3.569c.497 0 .926.228 1.223.568l.015-.011 2.651 3.184h.019a.682.682 0 0 0 .523.252.682.682 0 0 0 .523-.252h.018l2.652-3.184.015.011c.297-.34.726-.568 1.223-.568H23l-5.828 7z"/> <path fill="#15F9BB" fill-rule="evenodd" d="M17.172 15L23 22.001h-4.344.775c-.497 0-.926-.229-1.223-.569l-.015.012-2.654-3.187h-.011a.7.7 0 0 0-.528-.243.7.7 0 0 0-.528.243h-.012l-2.653 3.187-.015-.012c-.297.34-.726.569-1.223.569h.774-4.344L12.828 15 6.999 8h3.569l.001-.001c.497 0 .926.229 1.223.569l.014-.012 2.652 3.185h.012c.13.147.315.245.53.245.215 0 .4-.098.53-.245h.011l2.652-3.185.015.012A1.618 1.618 0 0 1 19.432 8h3.569l-5.829 7z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 604 B

After

Width:  |  Height:  |  Size: 587 B

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="101" height="36">
<path fill="#FFF" fill-rule="evenodd" d="M29.079 27.848l-10.126 6.457c-3.496 2.231-3.496 2.231-6.989.003L1.81 27.833C.003 26.553.003 24.511.003 24.511V11.464s0-2.222 1.823-3.337l10.138-6.465c3.493-2.225 3.493-2.225 6.992.005l10.123 6.455c1.833 1.177 1.831 3.338 1.831 3.338v13.052s.002 2.139-1.831 3.336zM19.45 11.883c-.429 0-.8.204-1.057.508l-.013-.01-2.294 2.85h-.01a.611.611 0 0 1-.45.201.608.608 0 0 1-.45-.201h-.027l-2.294-2.85-.012.01a1.381 1.381 0 0 0-1.058-.508H8.697l5.042 6.264-5.042 6.264h3.088c.43 0 .801-.204 1.058-.509l.013.011 2.281-2.834h.019a.608.608 0 0 1 .47-.23c.192 0 .356.093.469.23h.003l2.282 2.834.012-.011c.258.305.629.509 1.058.509h3.088l-5.041-6.264 5.041-6.264H19.45zM99.961 30.953l-2.563-3.675h-.028l.018.206c.033.39.05.748.05 1.072v2.397h-.774v-4.611h1.034l2.556 3.655h.021a19.955 19.955 0 0 1-.029-.528 16.461 16.461 0 0 1-.021-.712v-2.415h.781v4.611h-1.045zM97.22 20.801h-2.952V8.776h-3.78V6.199H101v2.577h-3.78v12.025zm-6.64 10.152l-.521-1.281h-1.992l-.51 1.281h-.898l1.949-4.63h.927l1.95 4.63h-.905zm-1.234-3.186a7.578 7.578 0 0 1-.148-.397 7.769 7.769 0 0 1-.13-.398 6.502 6.502 0 0 1-.281.849l-.471 1.202h1.519l-.489-1.256zm-7.989-6.966h-3.941V6.199h4.37c2.272 0 4.037.63 5.294 1.888 1.257 1.259 1.885 3.016 1.885 5.274 0 2.403-.652 4.244-1.957 5.523-1.304 1.278-3.188 1.917-5.651 1.917zm.581-12.065h-1.571v9.508h1.266c2.844 0 4.266-1.601 4.266-4.804 0-3.136-1.32-4.704-3.961-4.704zm-3.57 18.463a5.145 5.145 0 0 0-.558-.194 2.277 2.277 0 0 0-.618-.083c-.49 0-.875.153-1.155.46-.281.308-.421.731-.421 1.271 0 .567.135.994.405 1.284.269.291.66.436 1.171.436.221 0 .435-.02.641-.059a8.21 8.21 0 0 0 .645-.15v.647a4.36 4.36 0 0 1-1.39.205c-.763 0-1.348-.205-1.757-.613-.409-.409-.613-.995-.613-1.756 0-.479.099-.899.297-1.258a2 2 0 0 1 .861-.827c.376-.191.817-.287 1.323-.287a3.63 3.63 0 0 1 1.475.297l-.306.627zm-8.746-15.851c.264.19.887.531 1.871 1.024 1.301.652 2.193 1.307 2.676 1.962.482.656.723 1.46.723 2.412 0 1.319-.452 2.357-1.356 3.116-.905.759-2.163 1.139-3.776 1.139-1.485 0-2.799-.293-3.942-.879v-2.876c.94.439 1.735.749 2.386.929.65.179 1.245.269 1.785.269.647 0 1.144-.13 1.49-.389.346-.26.519-.646.519-1.159 0-.286-.076-.541-.229-.764a2.598 2.598 0 0 0-.671-.644c-.295-.206-.897-.536-1.804-.989-.851-.419-1.489-.822-1.914-1.208a4.513 4.513 0 0 1-1.019-1.349c-.254-.512-.381-1.112-.381-1.797 0-1.292.418-2.308 1.252-3.047.835-.739 1.989-1.108 3.461-1.108.724 0 1.414.09 2.071.269.657.18 1.344.433 2.062.759l-.952 2.407c-.743-.319-1.357-.542-1.843-.669a5.687 5.687 0 0 0-1.433-.19c-.558 0-.987.137-1.285.41-.299.273-.448.629-.448 1.069 0 .273.061.511.181.714.121.203.313.399.576.589zm-7.969 14.994h.851v3.964h2.207v.647h-3.058v-4.611zm-1.071-5.99c-.87.433-1.898.649-3.085.649-1.79 0-3.18-.481-4.171-1.443-.99-.962-1.485-2.279-1.485-3.95V6.199h2.942v8.939c0 1.126.216 1.951.648 2.477.431.526 1.145.789 2.142.789.965 0 1.665-.264 2.099-.794.435-.529.653-1.36.653-2.492V6.199h2.942v9.449c0 1.078-.23 2.024-.691 2.836-.46.813-1.125 1.435-1.994 1.868zm-6.7 10.601h-.905l-.521-1.281h-1.992l-.51 1.281h-.898l1.95-4.63h.926l1.95 4.63zm-2.286-3.583a8.04 8.04 0 0 1-.131-.398 6.502 6.502 0 0 1-.281.849l-.471 1.202h1.519l-.489-1.256a7.792 7.792 0 0 1-.147-.397zm-4.811-6.569l-2.237-3.825-2.247 3.825h-3.295l3.609-5.703-3.428-5.463h3.295l2.066 3.556 2.085-3.556h3.294l-3.465 5.463 3.627 5.703h-3.304zm-6.277 9.578c.338 0 .587-.057.747-.17a.534.534 0 0 0 .241-.458.55.55 0 0 0-.221-.439c-.148-.119-.452-.261-.913-.425-.475-.17-.81-.365-1.005-.583a1.145 1.145 0 0 1-.292-.789c0-.385.154-.688.463-.909.309-.22.724-.331 1.244-.331.499 0 .996.097 1.49.291l-.271.614c-.463-.172-.877-.258-1.24-.258-.276 0-.485.053-.628.159a.503.503 0 0 0-.213.422.54.54 0 0 0 .085.307.837.837 0 0 0 .282.241c.13.076.366.176.706.3.382.141.662.272.841.394.178.122.309.26.392.413.083.154.125.335.125.543 0 .41-.168.731-.503.965-.335.233-.797.35-1.387.35-.589 0-1.071-.081-1.447-.243v-.713c.238.099.49.177.758.234.267.056.516.085.746.085zm7.306-3.391h-1.533v3.965h-.852v-3.965h-1.533v-.646h3.918v.646zm10.991-.369c.319.185.479.477.479.877a.982.982 0 0 1-.235.672c-.157.179-.383.291-.677.337v.032c.366.061.635.181.807.361.172.18.258.423.258.73 0 .415-.163.739-.49.973-.327.235-.781.352-1.363.352h-1.882v-4.611h1.547c.717 0 1.236.092 1.556.277zm-2.251 3.7h.905c.356 0 .626-.061.807-.181.182-.121.273-.313.273-.573 0-.24-.093-.417-.278-.533-.185-.116-.467-.173-.845-.173h-.862v1.46zm0-2.072h.82c.356 0 .616-.05.78-.15.164-.1.246-.27.246-.509 0-.217-.088-.374-.265-.471-.178-.096-.458-.145-.843-.145h-.738v1.275zm13.135-1.268h-2.096v1.255h1.964v.631h-1.964v1.448h2.096v.64h-2.948v-4.611h2.948v.637zm11.896 1.249h2.402v-1.886h.856v4.611h-.856v-2.079h-2.402v2.079h-.852v-4.611h.852v1.886zm12.572 2.725h-.852v-4.611h.852v4.611z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="101" height="36">
<path fill="#12AC97" fill-rule="evenodd" d="M29.079 27.848l-10.126 6.457c-3.496 2.231-3.496 2.231-6.989.003L1.81 27.833C.003 26.553.003 24.511.003 24.511V11.464s0-2.222 1.823-3.337l10.138-6.465c3.493-2.225 3.493-2.225 6.992.005l10.123 6.455c1.833 1.177 1.831 3.338 1.831 3.338v13.052s.002 2.139-1.831 3.336zM19.45 11.883c-.429 0-.8.204-1.057.508l-.013-.01-2.294 2.85h-.01a.611.611 0 0 1-.45.201.608.608 0 0 1-.45-.201h-.027l-2.294-2.85-.012.01a1.381 1.381 0 0 0-1.058-.508H8.697l5.042 6.264-5.042 6.264h3.088c.43 0 .801-.204 1.058-.509l.013.011 2.281-2.834h.019a.608.608 0 0 1 .47-.23c.192 0 .356.093.469.23h.003l2.282 2.834.012-.011c.258.305.629.509 1.058.509h3.088l-5.041-6.264 5.041-6.264H19.45z"/>
<path fill="#333" fill-rule="evenodd" d="M99.961 30.953l-2.563-3.675h-.028l.018.206c.033.39.05.748.05 1.072v2.397h-.774v-4.611h1.034l2.556 3.655h.021a19.955 19.955 0 0 1-.029-.528 16.461 16.461 0 0 1-.021-.712v-2.415h.781v4.611h-1.045zM97.22 20.801h-2.952V8.776h-3.78V6.199H101v2.577h-3.78v12.025zm-6.64 10.152l-.521-1.281h-1.992l-.51 1.281h-.898l1.949-4.63h.927l1.95 4.63h-.905zm-1.234-3.186a7.578 7.578 0 0 1-.148-.397 7.769 7.769 0 0 1-.13-.398 6.502 6.502 0 0 1-.281.849l-.471 1.202h1.519l-.489-1.256zm-7.989-6.966h-3.941V6.199h4.37c2.272 0 4.037.63 5.294 1.888 1.257 1.259 1.885 3.016 1.885 5.274 0 2.403-.652 4.244-1.957 5.523-1.304 1.278-3.188 1.917-5.651 1.917zm.581-12.065h-1.571v9.508h1.266c2.844 0 4.266-1.601 4.266-4.804 0-3.136-1.32-4.704-3.961-4.704zm-3.57 18.463a5.145 5.145 0 0 0-.558-.194 2.277 2.277 0 0 0-.618-.083c-.49 0-.875.153-1.155.46-.281.308-.421.731-.421 1.271 0 .567.135.994.405 1.284.269.291.66.436 1.171.436.221 0 .435-.02.641-.059a8.21 8.21 0 0 0 .645-.15v.647a4.36 4.36 0 0 1-1.39.205c-.763 0-1.348-.205-1.757-.613-.409-.409-.613-.995-.613-1.756 0-.479.099-.899.297-1.258a2 2 0 0 1 .861-.827c.376-.191.817-.287 1.323-.287a3.63 3.63 0 0 1 1.475.297l-.306.627zm-8.746-15.851c.264.19.887.531 1.871 1.024 1.301.652 2.193 1.307 2.676 1.962.482.656.723 1.46.723 2.412 0 1.319-.452 2.357-1.356 3.116-.905.759-2.163 1.139-3.776 1.139-1.485 0-2.799-.293-3.942-.879v-2.876c.94.439 1.735.749 2.386.929.65.179 1.245.269 1.785.269.647 0 1.144-.13 1.49-.389.346-.26.519-.646.519-1.159 0-.286-.076-.541-.229-.764a2.598 2.598 0 0 0-.671-.644c-.295-.206-.897-.536-1.804-.989-.851-.419-1.489-.822-1.914-1.208a4.513 4.513 0 0 1-1.019-1.349c-.254-.512-.381-1.112-.381-1.797 0-1.292.418-2.308 1.252-3.047.835-.739 1.989-1.108 3.461-1.108.724 0 1.414.09 2.071.269.657.18 1.344.433 2.062.759l-.952 2.407c-.743-.319-1.357-.542-1.843-.669a5.687 5.687 0 0 0-1.433-.19c-.558 0-.987.137-1.285.41-.299.273-.448.629-.448 1.069 0 .273.061.511.181.714.121.203.313.399.576.589zm-7.969 14.994h.851v3.964h2.207v.647h-3.058v-4.611zm-1.071-5.99c-.87.433-1.898.649-3.085.649-1.79 0-3.18-.481-4.171-1.443-.99-.962-1.485-2.279-1.485-3.95V6.199h2.942v8.939c0 1.126.216 1.951.648 2.477.431.526 1.145.789 2.142.789.965 0 1.665-.264 2.099-.794.435-.529.653-1.36.653-2.492V6.199h2.942v9.449c0 1.078-.23 2.024-.691 2.836-.46.813-1.125 1.435-1.994 1.868zm-6.7 10.601h-.905l-.521-1.281h-1.992l-.51 1.281h-.898l1.95-4.63h.926l1.95 4.63zm-2.286-3.583a8.04 8.04 0 0 1-.131-.398 6.502 6.502 0 0 1-.281.849l-.471 1.202h1.519l-.489-1.256a7.792 7.792 0 0 1-.147-.397zm-4.811-6.569l-2.237-3.825-2.247 3.825h-3.295l3.609-5.703-3.428-5.463h3.295l2.066 3.556 2.085-3.556h3.294l-3.465 5.463 3.627 5.703h-3.304zm-6.277 9.578c.338 0 .587-.057.747-.17a.534.534 0 0 0 .241-.458.55.55 0 0 0-.221-.439c-.148-.119-.452-.261-.913-.425-.475-.17-.81-.365-1.005-.583a1.145 1.145 0 0 1-.292-.789c0-.385.154-.688.463-.909.309-.22.724-.331 1.244-.331.499 0 .996.097 1.49.291l-.271.614c-.463-.172-.877-.258-1.24-.258-.276 0-.485.053-.628.159a.503.503 0 0 0-.213.422.54.54 0 0 0 .085.307.837.837 0 0 0 .282.241c.13.076.366.176.706.3.382.141.662.272.841.394.178.122.309.26.392.413.083.154.125.335.125.543 0 .41-.168.731-.503.965-.335.233-.797.35-1.387.35-.589 0-1.071-.081-1.447-.243v-.713c.238.099.49.177.758.234.267.056.516.085.746.085zm7.306-3.391h-1.533v3.965h-.852v-3.965h-1.533v-.646h3.918v.646zm10.991-.369c.319.185.479.477.479.877a.982.982 0 0 1-.235.672c-.157.179-.383.291-.677.337v.032c.366.061.635.181.807.361.172.18.258.423.258.73 0 .415-.163.739-.49.973-.327.235-.781.352-1.363.352h-1.882v-4.611h1.547c.717 0 1.236.092 1.556.277zm-2.251 3.7h.905c.356 0 .626-.061.807-.181.182-.121.273-.313.273-.573 0-.24-.093-.417-.278-.533-.185-.116-.467-.173-.845-.173h-.862v1.46zm0-2.072h.82c.356 0 .616-.05.78-.15.164-.1.246-.27.246-.509 0-.217-.088-.374-.265-.471-.178-.096-.458-.145-.843-.145h-.738v1.275zm13.135-1.268h-2.096v1.255h1.964v.631h-1.964v1.448h2.096v.64h-2.948v-4.611h2.948v.637zm11.896 1.249h2.402v-1.886h.856v4.611h-.856v-2.079h-2.402v2.079h-.852v-4.611h.852v1.886zm12.572 2.725h-.852v-4.611h.852v4.611z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias BlockScoutWeb.AddressCoinBalanceView alias BlockScoutWeb.AddressCoinBalanceView
@ -60,12 +60,14 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do {:ok, address} <- Chain.hash_to_address(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render(conn, "index.html", render(conn, "index.html",
address: address, address: address,
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash), validation_count: validation_count,
current_path: current_path(conn) current_path: current_path(conn)
) )
else else

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.AddressContractController do defmodule BlockScoutWeb.AddressContractController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
@ -20,14 +20,16 @@ defmodule BlockScoutWeb.AddressContractController do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
:error -> :error ->

@ -69,6 +69,34 @@ defmodule BlockScoutWeb.AddressController do
redirect(conn, to: address_transaction_path(conn, :index, id)) redirect(conn, to: address_transaction_path(conn, :index, id))
end end
def transaction_and_validation_count(%Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash) do
transaction_count_task =
Task.async(fn ->
transaction_count(address_hash)
end)
validation_count_task =
Task.async(fn ->
validation_count(address_hash)
end)
[transaction_count_task, validation_count_task]
|> Task.yield_many(:timer.seconds(30))
|> Enum.map(fn {_task, res} ->
case res do
{:ok, result} ->
result
{:exit, reason} ->
raise "Query fetching address counters terminated: #{inspect(reason)}"
nil ->
raise "Query fetching address counters timed out."
end
end)
|> List.to_tuple()
end
def transaction_count(%Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash) do def transaction_count(%Hash{byte_count: unquote(Hash.Address.byte_count())} = address_hash) do
Chain.total_transactions_sent_by_address(address_hash) Chain.total_transactions_sent_by_address(address_hash)
end end

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.AddressDecompiledContractController do defmodule BlockScoutWeb.AddressDecompiledContractController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
alias Explorer.{Chain, Market} alias Explorer.{Chain, Market}
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
@ -10,14 +10,16 @@ defmodule BlockScoutWeb.AddressDecompiledContractController do
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_decompiled_contract_address(address_hash) do {:ok, address} <- Chain.find_decompiled_contract_address(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
:error -> :error ->

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias BlockScoutWeb.InternalTransactionView alias BlockScoutWeb.InternalTransactionView
@ -63,6 +63,8 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
def index(conn, %{"address_id" => address_hash_string} = params) do def index(conn, %{"address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do {:ok, address} <- Chain.hash_to_address(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
@ -71,8 +73,8 @@ defmodule BlockScoutWeb.AddressInternalTransactionController do
current_path: current_path(conn), current_path: current_path(conn),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"], filter: params["filter"],
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
:error -> :error ->

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.AddressLogsController do
Manages events logs tab. Manages events logs tab.
""" """
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias BlockScoutWeb.AddressLogsView alias BlockScoutWeb.AddressLogsView
@ -56,6 +56,8 @@ defmodule BlockScoutWeb.AddressLogsController do
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do {:ok, address} <- Chain.hash_to_address(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
@ -63,8 +65,8 @@ defmodule BlockScoutWeb.AddressLogsController do
current_path: current_path(conn), current_path: current_path(conn),
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
_ -> _ ->

@ -12,7 +12,7 @@ defmodule BlockScoutWeb.AddressReadContractController do
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Indexer.Fetcher.CoinBalanceOnDemand alias Indexer.Fetcher.CoinBalanceOnDemand
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
address_options = [ address_options = [
@ -27,14 +27,16 @@ defmodule BlockScoutWeb.AddressReadContractController do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
:error -> :error ->

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.AddressTokenController do defmodule BlockScoutWeb.AddressTokenController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1]
alias BlockScoutWeb.AddressTokenView alias BlockScoutWeb.AddressTokenView
@ -57,6 +57,8 @@ defmodule BlockScoutWeb.AddressTokenController do
def index(conn, %{"address_id" => address_hash_string} = _params) do def index(conn, %{"address_id" => address_hash_string} = _params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do {:ok, address} <- Chain.hash_to_address(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
@ -64,8 +66,8 @@ defmodule BlockScoutWeb.AddressTokenController do
current_path: current_path(conn), current_path: current_path(conn),
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
:error -> :error ->

@ -7,7 +7,7 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
alias Indexer.Fetcher.CoinBalanceOnDemand alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View alias Phoenix.View
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, import BlockScoutWeb.Chain,
only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1] only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1]
@ -77,6 +77,8 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
{:ok, token_hash} <- Chain.string_to_address_hash(token_hash_string), {:ok, token_hash} <- Chain.string_to_address_hash(token_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash), {:ok, address} <- Chain.hash_to_address(address_hash),
{:ok, token} <- Chain.token_from_address_hash(token_hash) do {:ok, token} <- Chain.token_from_address_hash(token_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
@ -85,8 +87,8 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
current_path: current_path(conn), current_path: current_path(conn),
token: token, token: token,
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash) validation_count: validation_count
) )
else else
:error -> :error ->

@ -5,7 +5,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1] import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias BlockScoutWeb.TransactionView alias BlockScoutWeb.TransactionView
@ -96,6 +96,8 @@ defmodule BlockScoutWeb.AddressTransactionController do
def index(conn, %{"address_id" => address_hash_string} = params) do def index(conn, %{"address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do {:ok, address} <- Chain.hash_to_address(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
@ -103,8 +105,8 @@ defmodule BlockScoutWeb.AddressTransactionController do
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(), exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"], filter: params["filter"],
transaction_count: transaction_count(address_hash), transaction_count: transaction_count,
validation_count: validation_count(address_hash), validation_count: validation_count,
current_path: current_path(conn) current_path: current_path(conn)
) )
else else

@ -4,7 +4,7 @@ defmodule BlockScoutWeb.AddressValidationController do
""" """
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1] import BlockScoutWeb.AddressController, only: [transaction_and_validation_count: 1]
import BlockScoutWeb.Chain, import BlockScoutWeb.Chain,
only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1] only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
@ -69,14 +69,16 @@ defmodule BlockScoutWeb.AddressValidationController do
def index(conn, %{"address_id" => address_hash_string}) do def index(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_or_insert_address_from_hash(address_hash) do {:ok, address} <- Chain.find_or_insert_address_from_hash(address_hash) do
{transaction_count, validation_count} = transaction_and_validation_count(address_hash)
render( render(
conn, conn,
"index.html", "index.html",
address: address, address: address,
coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address), coin_balance_status: CoinBalanceOnDemand.trigger_fetch(address),
current_path: current_path(conn), current_path: current_path(conn),
transaction_count: transaction_count(address.hash), transaction_count: transaction_count,
validation_count: validation_count(address.hash), validation_count: validation_count,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null() exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null()
) )
else else

@ -7,6 +7,7 @@ defmodule BlockScoutWeb.Notifier do
alias BlockScoutWeb.{AddressContractVerificationView, Endpoint} alias BlockScoutWeb.{AddressContractVerificationView, Endpoint}
alias Explorer.{Chain, Market, Repo} alias Explorer.{Chain, Market, Repo}
alias Explorer.Chain.{Address, InternalTransaction, Transaction} alias Explorer.Chain.{Address, InternalTransaction, Transaction}
alias Explorer.Chain.Supply.RSK
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Explorer.SmartContract.{Solidity.CodeCompiler, Solidity.CompilerVersion} alias Explorer.SmartContract.{Solidity.CodeCompiler, Solidity.CompilerVersion}
@ -76,8 +77,17 @@ defmodule BlockScoutWeb.Notifier do
data -> data data -> data
end end
exchange_rate_with_available_supply =
case Application.get_env(:explorer, :supply) do
RSK ->
%{exchange_rate | available_supply: nil, market_cap_usd: RSK.market_cap(exchange_rate)}
_ ->
exchange_rate
end
Endpoint.broadcast("exchange_rate:new_rate", "new_rate", %{ Endpoint.broadcast("exchange_rate:new_rate", "new_rate", %{
exchange_rate: exchange_rate, exchange_rate: exchange_rate_with_available_supply,
market_history_data: Enum.map(market_history_data, fn day -> Map.take(day, [:closing_price, :date]) end) market_history_data: Enum.map(market_history_data, fn day -> Map.take(day, [:closing_price, :date]) end)
}) })
end end

@ -66,7 +66,7 @@
</button> </button>
</div> </div>
<div class="tile tile-muted mb-4"> <div class="tile tile-muted mb-4">
<pre class="pre-scrollable line-numbers" data-activate-highlight><code class="solidity"><%= for {line, number} <- contract_lines_with_index(@address.smart_contract.contract_source_code) do %><div data-line-number="<%= number %>"><%= line %></div><% end %></code></pre> <pre class="pre-scrollable line-numbers" data-activate-highlight><code class="solidity"><%= for {line, number} <- contract_lines_with_index(@address.smart_contract.contract_source_code, @address.smart_contract.inserted_at) do %><div data-line-number="<%= number %>"><%= line %></div><% end %></code></pre>
</div> </div>
</section> </section>

@ -91,12 +91,49 @@
<%= gettext "Something went wrong, click to reload." %> <%= gettext "Something went wrong, click to reload." %>
</span> </span>
</button> </button>
<div hidden data-selector="loading-message" class="tile tile-muted text-center mt-3 w-100" > <div hidden data-selector="loading-message" class="col-lg-3" >
<span class="loading-spinner-small mr-2"> <div data-selector="chain-block">
<span class="loading-spinner-block-1"></span> <div class="tile tile-type-block n-p d-flex flex-column">
<span class="loading-spinner-block-2"></span> <a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
</span> <div class="tile-bottom-contents">
<%= gettext("Loading...") %> <div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div>
<div hidden data-selector="loading-message" class="col-lg-3" >
<div data-selector="chain-block">
<div class="tile tile-type-block n-p d-flex flex-column">
<a class="tile-title"><span class="tile-loader tile-label-loader"></span> </a>
<div class="tile-bottom-contents">
<div class="dark-block-loader"></div>
<div class="dark-block-loader"></div>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

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

@ -12,13 +12,27 @@
<%= link to: webapp_url(@conn), class: "navbar-brand", "data-test": "header_logo" do %> <%= link to: webapp_url(@conn), class: "navbar-brand", "data-test": "header_logo" do %>
<img class="navbar-logo" id="navbar-logo" src="<%= logo() %>" alt="<%= subnetwork_title() %>" /> <img class="navbar-logo" id="navbar-logo" src="<%= logo() %>" alt="<%= subnetwork_title() %>" />
<% end %> <% end %>
<a class="nav-link-new nav-link topnav-nav-link active-icon dropdown-toggle js-show-network-selector" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon">
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="6">
<circle cx="3" cy="3" r="3" fill="#80d6a1"></circle>
</svg> </span>Sokol Testnet</a>
<button class="new-button" id="dark-mode-changer">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="16">
<path fill="#a3a9b5" fill-rule="evenodd" d="M14.88 11.578a.544.544 0 0 0-.599-.166 5.7 5.7 0 0 1-1.924.321c-3.259 0-5.91-2.632-5.91-5.866 0-1.947.968-3.759 2.59-4.849a.534.534 0 0 0-.225-.97A5.289 5.289 0 0 0 8.059 0C3.615 0 0 3.588 0 8s3.615 8 8.059 8c2.82 0 5.386-1.423 6.862-3.806a.533.533 0 0 0-.041-.616z"></path>
</svg>
</button>
<script> <script>
if (localStorage.getItem("current-color-mode") === "dark") { if (localStorage.getItem("current-color-mode") === "dark") {
document.getElementById("navbar-logo").style.filter = "brightness(0) invert(1)"; document.getElementById("navbar-logo").style.filter = "brightness(0) invert(1)";
} }
</script> </script>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="<%= gettext("Toggle navigation") %>"> <button class="navbar-toggler" id="toggleButton" onclick="switchVisible(); type="button" value="Click" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="<%= gettext("Toggle navigation") %>">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon" id="toggleImage1" style="width="26px;"></span>
<span class="navbar-toggler-icon-1" id="toggleImage2"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 47.971 47.971" style="enable-background:new 0 0 47.971 47.971; width: 17px;
transform: translate(0px, -1.5px);" xml:space="preserve"> <g><g>
<path d="M28.228,23.986L47.092,5.122c1.172-1.171,1.172-3.071,0-4.242c-1.172-1.172-3.07-1.172-4.242,0L23.986,19.744L5.121,0.88 c-1.172-1.172-3.07-1.172-4.242,0c-1.172,1.171-1.172,3.071,0,4.242l18.865,18.864L0.879,42.85c-1.172,1.171-1.172,3.071,0,4.242 C1.465,47.677,2.233,47.97,3,47.97s1.535-0.293,2.121-0.879l18.865-18.864L42.85,47.091c0.586,0.586,1.354,0.879,2.121,0.879 s1.535-0.293,2.121-0.879c1.172-1.171,1.172-3.071,0-4.242L28.228,23.986z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#a3a9b5"/>
</g></g> </svg></span>
</button> </button>
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav"> <ul class="navbar-nav">
@ -30,7 +44,7 @@
</span> </span>
<%= gettext("Blocks") %> <%= gettext("Blocks") %>
</a> </a>
<div class="dropdown-menu" aria-labelledby="navbarBlocksDropdown"> <div class="dropdown-menu" id="checkIfSmall" aria-labelledby="navbarBlocksDropdown">
<%= link to: block_path(@conn, :index), class: "dropdown-item #{tab_status("blocks", @conn.request_path)}" do %> <%= link to: block_path(@conn, :index), class: "dropdown-item #{tab_status("blocks", @conn.request_path)}" do %>
<%= gettext("Blocks") %> <%= gettext("Blocks") %>
<% end %> <% end %>
@ -42,14 +56,14 @@
<% end %> <% end %>
</div> </div>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown" id="activeTransactions">
<a href="#" role="button" id="navbarTransactionsDropdown" class="nav-link topnav-nav-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a href="#" role="button" id="navbarTransactionsDropdown1" class="nav-link topnav-nav-link dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon"> <span class="nav-link-icon">
<%= render BlockScoutWeb.IconsView, "_transaction_icon.html" %> <%= render BlockScoutWeb.IconsView, "_transaction_icon.html" %>
</span> </span>
<%= gettext("Transactions") %> <%= gettext("Transactions") %>
</a> </a>
<div class="dropdown-menu" aria-labeledby="navbarTransactionsDropdown"> <div class="dropdown-menu" id="checkIfSmall1" aria-labeledby="navbarTransactionsDropdown">
<%= link( <%= link(
gettext("Validated"), gettext("Validated"),
class: "dropdown-item #{tab_status("txs", @conn.request_path)}", class: "dropdown-item #{tab_status("txs", @conn.request_path)}",
@ -80,7 +94,7 @@
</span> </span>
<%= gettext("APIs") %> <%= gettext("APIs") %>
</a> </a>
<div class="dropdown-menu" aria-labeledby="navbarTransactionsDropdown"> <div class="dropdown-menu" id="checkIfSmall2" aria-labeledby="navbarTransactionsDropdown">
<%= link( <%= link(
gettext("GraphQL"), gettext("GraphQL"),
class: "dropdown-item #{tab_status("graphiql", @conn.request_path)}", class: "dropdown-item #{tab_status("graphiql", @conn.request_path)}",
@ -100,7 +114,7 @@
</li> </li>
<% end %> <% end %>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link topnav-nav-link active-icon <%= if dropdown_nets() != [], do: "dropdown-toggle js-show-network-selector" %>" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link last-child topnav-nav-link active-icon <%= if dropdown_nets() != [], do: "dropdown-toggle js-show-network-selector" %>" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon"> <span class="nav-link-icon">
<%= render BlockScoutWeb.IconsView, "_active_icon.html" %> <%= render BlockScoutWeb.IconsView, "_active_icon.html" %>
</span> </span>
@ -108,7 +122,7 @@
</a> </a>
</li> </li>
</ul> </ul>
<!-- Dark mode changer --> <!-- Dark mode changer was there -->
<button class="dark-mode-changer" id="dark-mode-changer"> <button class="dark-mode-changer" id="dark-mode-changer">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="16"> <svg xmlns="http://www.w3.org/2000/svg" width="15" height="16">
<path fill="#9B62FF" fill-rule="evenodd" d="M14.88 11.578a.544.544 0 0 0-.599-.166 5.7 5.7 0 0 1-1.924.321c-3.259 0-5.91-2.632-5.91-5.866 0-1.947.968-3.759 2.59-4.849a.534.534 0 0 0-.225-.97A5.289 5.289 0 0 0 8.059 0C3.615 0 0 3.588 0 8s3.615 8 8.059 8c2.82 0 5.386-1.423 6.862-3.806a.533.533 0 0 0-.041-.616z"/> <path fill="#9B62FF" fill-rule="evenodd" d="M14.88 11.578a.544.544 0 0 0-.599-.166 5.7 5.7 0 0 1-1.924.321c-3.259 0-5.91-2.632-5.91-5.866 0-1.947.968-3.759 2.59-4.849a.534.534 0 0 0-.225-.97A5.289 5.289 0 0 0 8.059 0C3.615 0 0 3.588 0 8s3.615 8 8.059 8c2.82 0 5.386-1.423 6.862-3.806a.533.533 0 0 0-.041-.616z"/>

@ -19,7 +19,7 @@
</div> </div>
<% end %> <% end %>
<input type="submit" value='<%= gettext("Query")%>' class="button button-secondary button-xs py-0 mt-2" /> <input type="submit" value='<%= gettext("Query")%>' class="button btn-line button-xs py-0 mt-2" style="padding: 6px 8px!important;height: 26px;font-size: 11px;" />
</form> </form>
<div class='p-2 text-muted <%= if (queryable?(function["inputs"]) == true), do: "w-100" %>'> <div class='p-2 text-muted <%= if (queryable?(function["inputs"]) == true), do: "w-100" %>'>

@ -2,7 +2,7 @@ defmodule BlockScoutWeb.AddressContractView do
use BlockScoutWeb, :view use BlockScoutWeb, :view
alias ABI.{FunctionSelector, TypeDecoder} alias ABI.{FunctionSelector, TypeDecoder}
alias Explorer.Chain.{Address, Data, InternalTransaction} alias Explorer.Chain.{Address, Data, InternalTransaction, SmartContract}
def render("scripts.html", %{conn: conn}) do def render("scripts.html", %{conn: conn}) do
render_scripts(conn, "address_contract/code_highlighting.js") render_scripts(conn, "address_contract/code_highlighting.js")
@ -63,8 +63,11 @@ defmodule BlockScoutWeb.AddressContractView do
end) end)
end end
def contract_lines_with_index(contract_source_code) do def contract_lines_with_index(source_code, inserted_at \\ nil) do
contract_lines = String.split(contract_source_code, "\n") contract_lines =
source_code
|> String.split("\n")
|> SmartContract.add_submitted_comment(inserted_at)
max_digits = max_digits =
contract_lines contract_lines

@ -112,12 +112,12 @@ msgid "API for the %{subnetwork} - BlockScout"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:81 #: lib/block_scout_web/templates/layout/_topnav.html.eex:95
msgid "APIs" msgid "APIs"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:71 #: lib/block_scout_web/templates/layout/_topnav.html.eex:85
msgid "Accounts" msgid "Accounts"
msgstr "" msgstr ""
@ -238,8 +238,8 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:87 #: lib/block_scout_web/templates/chain/show.html.eex:87
#: lib/block_scout_web/templates/layout/_topnav.html.eex:31 #: lib/block_scout_web/templates/layout/_topnav.html.eex:45
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35 #: lib/block_scout_web/templates/layout/_topnav.html.eex:49
msgid "Blocks" msgid "Blocks"
msgstr "" msgstr ""
@ -683,7 +683,7 @@ msgid "Error: Could not determine contract creator."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:95 #: lib/block_scout_web/templates/layout/_topnav.html.eex:109
msgid "Eth RPC" msgid "Eth RPC"
msgstr "" msgstr ""
@ -749,7 +749,7 @@ msgid "For any existing contracts in the database, insert all ABI entries into t
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:41 #: lib/block_scout_web/templates/layout/_topnav.html.eex:55
msgid "Forked Blocks (Reorgs)" msgid "Forked Blocks (Reorgs)"
msgstr "" msgstr ""
@ -787,7 +787,7 @@ msgid "Github"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:85 #: lib/block_scout_web/templates/layout/_topnav.html.eex:99
msgid "GraphQL" msgid "GraphQL"
msgstr "" msgstr ""
@ -912,7 +912,7 @@ msgid "To"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:20 #: lib/block_scout_web/templates/layout/_topnav.html.eex:30
msgid "Toggle navigation" msgid "Toggle navigation"
msgstr "" msgstr ""
@ -1090,7 +1090,6 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_read_contract/index.html.eex:14 #: 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/tokens/read_contract/index.html.eex:21 #: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:21
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr ""
@ -1168,7 +1167,7 @@ msgid "More internal transactions have come in"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:111 #: lib/block_scout_web/templates/chain/show.html.eex:148
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:10 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:10
#: lib/block_scout_web/templates/transaction/index.html.eex:10 #: lib/block_scout_web/templates/transaction/index.html.eex:10
msgid "More transactions have come in" msgid "More transactions have come in"
@ -1252,7 +1251,7 @@ msgid "Parent Hash"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:59 #: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/views/transaction_view.ex:183 #: lib/block_scout_web/views/transaction_view.ex:183
#: lib/block_scout_web/views/transaction_view.ex:217 #: lib/block_scout_web/views/transaction_view.ex:217
msgid "Pending" msgid "Pending"
@ -1288,7 +1287,7 @@ msgid "Query"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:90 #: lib/block_scout_web/templates/layout/_topnav.html.eex:104
msgid "RPC" msgid "RPC"
msgstr "" msgstr ""
@ -1354,14 +1353,14 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14 #: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:127 #: lib/block_scout_web/templates/layout/_topnav.html.eex:141
#: lib/block_scout_web/templates/layout/_topnav.html.eex:144 #: lib/block_scout_web/templates/layout/_topnav.html.eex:158
msgid "Search" msgid "Search"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:121 #: lib/block_scout_web/templates/layout/_topnav.html.eex:135
#: lib/block_scout_web/templates/layout/_topnav.html.eex:125 #: lib/block_scout_web/templates/layout/_topnav.html.eex:139
msgid "Search by address, token symbol name, transaction hash, or block number" msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr "" msgstr ""
@ -1431,7 +1430,7 @@ msgid "Something went wrong, click to reload."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:117 #: lib/block_scout_web/templates/chain/show.html.eex:154
msgid "Something went wrong, click to retry." msgid "Something went wrong, click to retry."
msgstr "" msgstr ""
@ -1595,8 +1594,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_transaction/index.html.eex:15 #: lib/block_scout_web/templates/address_transaction/index.html.eex:15
#: lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: 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/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:108 #: lib/block_scout_web/templates/chain/show.html.eex:145
#: lib/block_scout_web/templates/layout/_topnav.html.eex:50 #: lib/block_scout_web/templates/layout/_topnav.html.eex:64
#: lib/block_scout_web/views/address_view.ex:305 #: lib/block_scout_web/views/address_view.ex:305
msgid "Transactions" msgid "Transactions"
msgstr "" msgstr ""
@ -1648,7 +1647,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:81 #: lib/block_scout_web/templates/block/overview.html.eex:81
#: lib/block_scout_web/templates/layout/_topnav.html.eex:38 #: lib/block_scout_web/templates/layout/_topnav.html.eex:52
msgid "Uncles" msgid "Uncles"
msgstr "" msgstr ""
@ -1668,7 +1667,7 @@ msgid "Used"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:54 #: lib/block_scout_web/templates/layout/_topnav.html.eex:68
msgid "Validated" msgid "Validated"
msgstr "" msgstr ""
@ -1732,7 +1731,7 @@ msgid "View All Blocks"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:107 #: lib/block_scout_web/templates/chain/show.html.eex:144
msgid "View All Transactions" msgid "View All Transactions"
msgstr "" msgstr ""

@ -112,12 +112,12 @@ msgid "API for the %{subnetwork} - BlockScout"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:81 #: lib/block_scout_web/templates/layout/_topnav.html.eex:95
msgid "APIs" msgid "APIs"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:71 #: lib/block_scout_web/templates/layout/_topnav.html.eex:85
msgid "Accounts" msgid "Accounts"
msgstr "" msgstr ""
@ -238,8 +238,8 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:87 #: lib/block_scout_web/templates/chain/show.html.eex:87
#: lib/block_scout_web/templates/layout/_topnav.html.eex:31 #: lib/block_scout_web/templates/layout/_topnav.html.eex:45
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35 #: lib/block_scout_web/templates/layout/_topnav.html.eex:49
msgid "Blocks" msgid "Blocks"
msgstr "" msgstr ""
@ -683,7 +683,7 @@ msgid "Error: Could not determine contract creator."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:95 #: lib/block_scout_web/templates/layout/_topnav.html.eex:109
msgid "Eth RPC" msgid "Eth RPC"
msgstr "" msgstr ""
@ -749,7 +749,7 @@ msgid "For any existing contracts in the database, insert all ABI entries into t
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:41 #: lib/block_scout_web/templates/layout/_topnav.html.eex:55
msgid "Forked Blocks (Reorgs)" msgid "Forked Blocks (Reorgs)"
msgstr "" msgstr ""
@ -787,7 +787,7 @@ msgid "Github"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:85 #: lib/block_scout_web/templates/layout/_topnav.html.eex:99
msgid "GraphQL" msgid "GraphQL"
msgstr "" msgstr ""
@ -912,7 +912,7 @@ msgid "To"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:20 #: lib/block_scout_web/templates/layout/_topnav.html.eex:30
msgid "Toggle navigation" msgid "Toggle navigation"
msgstr "" msgstr ""
@ -1090,7 +1090,6 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_read_contract/index.html.eex:14 #: 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/tokens/read_contract/index.html.eex:21 #: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:21
msgid "Loading..." msgid "Loading..."
msgstr "" msgstr ""
@ -1168,7 +1167,7 @@ msgid "More internal transactions have come in"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:111 #: lib/block_scout_web/templates/chain/show.html.eex:148
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:10 #: lib/block_scout_web/templates/pending_transaction/index.html.eex:10
#: lib/block_scout_web/templates/transaction/index.html.eex:10 #: lib/block_scout_web/templates/transaction/index.html.eex:10
msgid "More transactions have come in" msgid "More transactions have come in"
@ -1252,7 +1251,7 @@ msgid "Parent Hash"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:59 #: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/views/transaction_view.ex:183 #: lib/block_scout_web/views/transaction_view.ex:183
#: lib/block_scout_web/views/transaction_view.ex:217 #: lib/block_scout_web/views/transaction_view.ex:217
msgid "Pending" msgid "Pending"
@ -1288,7 +1287,7 @@ msgid "Query"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:90 #: lib/block_scout_web/templates/layout/_topnav.html.eex:104
msgid "RPC" msgid "RPC"
msgstr "" msgstr ""
@ -1354,14 +1353,14 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14 #: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:127 #: lib/block_scout_web/templates/layout/_topnav.html.eex:141
#: lib/block_scout_web/templates/layout/_topnav.html.eex:144 #: lib/block_scout_web/templates/layout/_topnav.html.eex:158
msgid "Search" msgid "Search"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:121 #: lib/block_scout_web/templates/layout/_topnav.html.eex:135
#: lib/block_scout_web/templates/layout/_topnav.html.eex:125 #: lib/block_scout_web/templates/layout/_topnav.html.eex:139
msgid "Search by address, token symbol name, transaction hash, or block number" msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr "" msgstr ""
@ -1431,7 +1430,7 @@ msgid "Something went wrong, click to reload."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:117 #: lib/block_scout_web/templates/chain/show.html.eex:154
msgid "Something went wrong, click to retry." msgid "Something went wrong, click to retry."
msgstr "" msgstr ""
@ -1595,8 +1594,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_transaction/index.html.eex:15 #: lib/block_scout_web/templates/address_transaction/index.html.eex:15
#: lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: 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/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:108 #: lib/block_scout_web/templates/chain/show.html.eex:145
#: lib/block_scout_web/templates/layout/_topnav.html.eex:50 #: lib/block_scout_web/templates/layout/_topnav.html.eex:64
#: lib/block_scout_web/views/address_view.ex:305 #: lib/block_scout_web/views/address_view.ex:305
msgid "Transactions" msgid "Transactions"
msgstr "" msgstr ""
@ -1648,7 +1647,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:81 #: lib/block_scout_web/templates/block/overview.html.eex:81
#: lib/block_scout_web/templates/layout/_topnav.html.eex:38 #: lib/block_scout_web/templates/layout/_topnav.html.eex:52
msgid "Uncles" msgid "Uncles"
msgstr "" msgstr ""
@ -1668,7 +1667,7 @@ msgid "Used"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:54 #: lib/block_scout_web/templates/layout/_topnav.html.eex:68
msgid "Validated" msgid "Validated"
msgstr "" msgstr ""
@ -1732,7 +1731,7 @@ msgid "View All Blocks"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:107 #: lib/block_scout_web/templates/chain/show.html.eex:144
msgid "View All Transactions" msgid "View All Transactions"
msgstr "" msgstr ""

@ -1,6 +1,6 @@
defmodule BlockScoutWeb.API.RPC.ContractControllerTest do defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
use BlockScoutWeb.ConnCase use BlockScoutWeb.ConnCase
alias Explorer.Factory alias Explorer.{Chain, Factory}
describe "listcontracts" do describe "listcontracts" do
setup do setup do
@ -450,7 +450,9 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
expected_result = [ expected_result = [
%{ %{
"Address" => to_string(contract.address_hash), "Address" => to_string(contract.address_hash),
"SourceCode" => contract.contract_source_code, "SourceCode" =>
"/**\n* Submitted for verification at blockscout.com on #{contract.inserted_at}\n*/\n" <>
contract.contract_source_code,
"ABI" => Jason.encode!(contract.abi), "ABI" => Jason.encode!(contract.abi),
"ContractName" => contract.name, "ContractName" => contract.name,
"CompilerVersion" => contract.compiler_version, "CompilerVersion" => contract.compiler_version,
@ -496,9 +498,13 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
|> get("/api", params) |> get("/api", params)
|> json_response(200) |> json_response(200)
verified_contract = Chain.address_hash_to_smart_contract(contract_address.hash)
expected_result = %{ expected_result = %{
"Address" => to_string(contract_address.hash), "Address" => to_string(contract_address.hash),
"SourceCode" => contract_code_info.source_code, "SourceCode" =>
"/**\n* Submitted for verification at blockscout.com on #{verified_contract.inserted_at}\n*/\n" <>
contract_code_info.source_code,
"ABI" => Jason.encode!(contract_code_info.abi), "ABI" => Jason.encode!(contract_code_info.abi),
"ContractName" => contract_code_info.name, "ContractName" => contract_code_info.name,
"CompilerVersion" => contract_code_info.version, "CompilerVersion" => contract_code_info.version,
@ -563,8 +569,14 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
result = response["result"] result = response["result"]
verified_contract = Chain.address_hash_to_smart_contract(contract_address.hash)
assert result["Address"] == to_string(contract_address.hash) assert result["Address"] == to_string(contract_address.hash)
assert result["SourceCode"] == contract_source_code
assert result["SourceCode"] ==
"/**\n* Submitted for verification at blockscout.com on #{verified_contract.inserted_at}\n*/\n" <>
contract_source_code
assert result["ContractName"] == name assert result["ContractName"] == name
assert result["DecompiledSourceCode"] == "Contract source code not decompiled." assert result["DecompiledSourceCode"] == "Contract source code not decompiled."
assert result["DecompilerVersion"] == "" assert result["DecompilerVersion"] == ""

@ -38,22 +38,25 @@ defmodule BlockScoutWeb.AddressContractViewTest do
result = AddressContractView.contract_lines_with_index(code) result = AddressContractView.contract_lines_with_index(code)
assert result == [ assert result == [
{"pragma solidity >=0.4.22 <0.6.0;", " 1"}, {"/**", " 1"},
{"", " 2"}, {"* Submitted for verification at blockscout.com on ", " 2"},
{"struct Proposal {", " 3"}, {"*/", " 3"},
{" uint voteCount;", " 4"}, {"pragma solidity >=0.4.22 <0.6.0;", " 4"},
{"}", " 5"}, {"", " 5"},
{"", " 6"}, {"struct Proposal {", " 6"},
{"address chairperson;", " 7"}, {" uint voteCount;", " 7"},
{"mapping(address => Voter) voters;", " 8"}, {"}", " 8"},
{"Proposal[] proposals;", " 9"}, {"", " 9"},
{"", "10"}, {"address chairperson;", "10"},
{"constructor(uint8 _numProposals) public {", "11"}, {"mapping(address => Voter) voters;", "11"},
{" chairperson = msg.sender;", "12"}, {"Proposal[] proposals;", "12"},
{" voters[chairperson].weight = 1;", "13"}, {"", "13"},
{" proposals.length = _numProposals;", "14"}, {"constructor(uint8 _numProposals) public {", "14"},
{"}", "15"}, {" chairperson = msg.sender;", "15"},
{"", "16"} {" voters[chairperson].weight = 1;", "16"},
{" proposals.length = _numProposals;", "17"},
{"}", "18"},
{"", "19"}
] ]
end end
@ -66,7 +69,17 @@ defmodule BlockScoutWeb.AddressContractViewTest do
test "returns a list of tuples and the first element is just a line from the original string" do test "returns a list of tuples and the first element is just a line from the original string" do
result = AddressContractView.contract_lines_with_index("a\nb\nc\nd\ne") result = AddressContractView.contract_lines_with_index("a\nb\nc\nd\ne")
assert Enum.map(result, fn {line, _number} -> line end) == ["a", "b", "c", "d", "e"]
assert Enum.map(result, fn {line, _number} -> line end) == [
"/**",
"* Submitted for verification at blockscout.com on ",
"*/",
"a",
"b",
"c",
"d",
"e"
]
end end
end end
end end

@ -61,9 +61,7 @@ defmodule EthereumJSONRPC.Receipts do
""" """
@spec elixir_to_logs(elixir) :: Logs.elixir() @spec elixir_to_logs(elixir) :: Logs.elixir()
def elixir_to_logs(elixir) when is_list(elixir) do def elixir_to_logs(elixir) when is_list(elixir) do
elixir Enum.flat_map(elixir, &Receipt.elixir_to_logs/1)
|> Enum.flat_map(&Receipt.elixir_to_logs/1)
|> Enum.filter(&(Map.get(&1, "type") != "pending"))
end end
@doc """ @doc """

@ -14,7 +14,7 @@ config :explorer,
System.get_env("ALLOWED_EVM_VERSIONS") || System.get_env("ALLOWED_EVM_VERSIONS") ||
"homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg,default", "homestead,tangerineWhistle,spuriousDragon,byzantium,constantinople,petersburg,default",
include_uncles_in_average_block_time: include_uncles_in_average_block_time:
if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "false", do: false, else: true), if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "true", do: true, else: false),
healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5) healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5)
average_block_period = average_block_period =
@ -27,11 +27,16 @@ config :explorer, Explorer.Counters.AverageBlockTime,
enabled: true, enabled: true,
period: average_block_period period: average_block_period
config :explorer, Explorer.ChainSpec.GenesisData, enabled: false, chain_spec_path: System.get_env("CHAIN_SPEC_PATH") config :explorer, Explorer.ChainSpec.GenesisData,
enabled: true,
config :explorer, Explorer.Chain.Cache.BlockNumber, enabled: true chain_spec_path: System.get_env("CHAIN_SPEC_PATH"),
emission_format: System.get_env("EMISSION_FORMAT", "DEFAULT"),
rewards_contract_address: System.get_env("REWARDS_CONTRACT_ADDRESS", "0xeca443e8e1ab29971a45a9c57a6a9875701698a5")
config :explorer, Explorer.ExchangeRates.Source.CoinGecko, coin_id: System.get_env("COIN_GECKO_ID", "poa-network") config :explorer, Explorer.Chain.Cache.BlockNumber,
enabled: true,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
balances_update_interval = balances_update_interval =
if System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do if System.get_env("ADDRESS_WITH_BALANCES_UPDATE_INTERVAL") do
@ -123,6 +128,14 @@ market_history_cache_period =
config :explorer, Explorer.Market.MarketHistoryCache, period: market_history_cache_period config :explorer, Explorer.Market.MarketHistoryCache, period: market_history_cache_period
config :explorer, Explorer.Chain.Cache.Blocks,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
config :explorer, Explorer.Chain.Cache.Transactions,
ttl_check_interval: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(1), else: false),
global_ttl: if(System.get_env("DISABLE_INDEXER") == "true", do: :timer.seconds(5))
# Import environment specific config. This must remain at the bottom # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs" import_config "#{Mix.env()}.exs"

@ -56,9 +56,7 @@ defmodule Explorer.Application do
opts = [strategy: :one_for_one, name: Explorer.Supervisor] opts = [strategy: :one_for_one, name: Explorer.Supervisor]
res = Supervisor.start_link(children, opts) Supervisor.start_link(children, opts)
res
end end
defp configurable_children do defp configurable_children do

@ -2592,8 +2592,26 @@ defmodule Explorer.Chain do
@spec address_hash_to_address_with_source_code(Hash.Address.t()) :: Address.t() | nil @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 def address_hash_to_address_with_source_code(address_hash) do
case Repo.get(Address, address_hash) do case Repo.get(Address, address_hash) do
nil -> nil nil ->
address -> Repo.preload(address, [:smart_contract, :decompiled_smart_contracts]) nil
address ->
address_with_smart_contract = Repo.preload(address, [:smart_contract, :decompiled_smart_contracts])
if address_with_smart_contract.smart_contract do
formatted_code =
SmartContract.add_submitted_comment(
address_with_smart_contract.smart_contract.contract_source_code,
address_with_smart_contract.smart_contract.inserted_at
)
%{
address_with_smart_contract
| smart_contract: %{address_with_smart_contract.smart_contract | contract_source_code: formatted_code}
}
else
address_with_smart_contract
end
end end
end end

@ -28,8 +28,8 @@ defmodule Explorer.Chain.Cache.BlockCount do
defp handle_fallback(:async_task) do defp handle_fallback(:async_task) do
# If this gets called it means an async task was requested, but none exists # If this gets called it means an async task was requested, but none exists
# so a new one needs to be launched # so a new one needs to be launched
task = {:ok, task} =
Task.async(fn -> Task.start(fn ->
try do try do
result = Chain.fetch_count_consensus_block() result = Chain.fetch_count_consensus_block()

@ -7,7 +7,9 @@ defmodule Explorer.Chain.Cache.BlockNumber do
use Explorer.Chain.MapCache, use Explorer.Chain.MapCache,
name: :block_number, name: :block_number,
keys: [:min, :max] keys: [:min, :max],
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
alias Explorer.Chain alias Explorer.Chain

@ -11,7 +11,9 @@ defmodule Explorer.Chain.Cache.Blocks do
ids_list_key: "block_numbers", ids_list_key: "block_numbers",
preload: :transactions, preload: :transactions,
preload: [miner: :names], preload: [miner: :names],
preload: :rewards preload: :rewards,
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
@type element :: Block.t() @type element :: Block.t()

@ -29,8 +29,8 @@ defmodule Explorer.Chain.Cache.TransactionCount do
defp handle_fallback(:async_task) do defp handle_fallback(:async_task) do
# If this gets called it means an async task was requested, but none exists # If this gets called it means an async task was requested, but none exists
# so a new one needs to be launched # so a new one needs to be launched
task = {:ok, task} =
Task.async(fn -> Task.start(fn ->
try do try do
result = Repo.aggregate(Transaction, :count, :hash, timeout: :infinity) result = Repo.aggregate(Transaction, :count, :hash, timeout: :infinity)

@ -16,7 +16,9 @@ defmodule Explorer.Chain.Cache.Transactions do
token_transfers: :token, token_transfers: :token,
token_transfers: :from_address, token_transfers: :from_address,
token_transfers: :to_address token_transfers: :to_address
] ],
ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
@type element :: Transaction.t() @type element :: Transaction.t()

@ -9,7 +9,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
alias Ecto.Adapters.SQL alias Ecto.Adapters.SQL
alias Ecto.{Changeset, Multi, Repo} alias Ecto.{Changeset, Multi, Repo}
alias Explorer.Chain.{Address, Block, Hash, Import, InternalTransaction, Transaction} alias Explorer.Chain.{Address, Block, Hash, Import, InternalTransaction, Log, TokenTransfer, Transaction}
alias Explorer.Chain.Block.Reward alias Explorer.Chain.Block.Reward
alias Explorer.Chain.Import.Runner alias Explorer.Chain.Import.Runner
alias Explorer.Chain.Import.Runner.Address.CurrentTokenBalances alias Explorer.Chain.Import.Runner.Address.CurrentTokenBalances
@ -58,6 +58,31 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
where_forked: where_forked where_forked: where_forked
}) })
end) end)
|> Multi.run(:lose_consensus, fn repo, _ ->
lose_consensus(repo, ordered_consensus_block_numbers, insert_options)
end)
|> Multi.run(:lose_invalid_neighbour_consensus, fn repo, _ ->
lose_invalid_neighbour_consensus(repo, where_invalid_neighbour, insert_options)
end)
|> Multi.run(:remove_nonconsensus_data, fn repo,
%{
lose_consensus: lost_consensus_blocks,
lose_invalid_neighbour_consensus: lost_consensus_neighbours
} ->
nonconsensus_block_numbers =
(lost_consensus_blocks ++ lost_consensus_neighbours)
|> Enum.map(fn %{number: number} ->
number
end)
|> Enum.sort()
|> Enum.dedup()
remove_nonconsensus_data(
repo,
nonconsensus_block_numbers,
insert_options
)
end)
# MUST be after `:derive_transaction_forks`, which depends on values in `transactions` table # MUST be after `:derive_transaction_forks`, which depends on values in `transactions` table
|> Multi.run(:fork_transactions, fn repo, _ -> |> Multi.run(:fork_transactions, fn repo, _ ->
fork_transactions(%{ fork_transactions(%{
@ -67,12 +92,6 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
where_forked: where_forked where_forked: where_forked
}) })
end) end)
|> Multi.run(:lose_consensus, fn repo, _ ->
lose_consensus(repo, ordered_consensus_block_numbers, insert_options)
end)
|> Multi.run(:lose_invalid_neighbour_consensus, fn repo, _ ->
lose_invalid_neighbour_consensus(repo, where_invalid_neighbour, insert_options)
end)
|> Multi.run(:delete_address_token_balances, fn repo, _ -> |> Multi.run(:delete_address_token_balances, fn repo, _ ->
delete_address_token_balances(repo, ordered_consensus_block_numbers, insert_options) delete_address_token_balances(repo, ordered_consensus_block_numbers, insert_options)
end) end)
@ -342,6 +361,136 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
end end
end end
defp remove_nonconsensus_data(
repo,
nonconsensus_block_numbers,
insert_options
) do
with {:ok, deleted_token_transfers} <-
remove_nonconsensus_token_transfers(repo, nonconsensus_block_numbers, insert_options),
{:ok, deleted_logs} <- remove_nonconsensus_logs(repo, nonconsensus_block_numbers, insert_options),
{:ok, deleted_internal_transactions} <-
remove_nonconsensus_internal_transactions(repo, nonconsensus_block_numbers, insert_options) do
{:ok,
%{
token_transfers: deleted_token_transfers,
logs: deleted_logs,
internal_transactions: deleted_internal_transactions
}}
end
end
defp remove_nonconsensus_token_transfers(repo, nonconsensus_block_numbers, %{timeout: timeout}) do
ordered_token_transfers =
from(token_transfer in TokenTransfer,
where: token_transfer.block_number in ^nonconsensus_block_numbers,
select: map(token_transfer, [:transaction_hash, :log_index]),
# Enforce TokenTransfer ShareLocks order (see docs: sharelocks.md)
order_by: [
token_transfer.transaction_hash,
token_transfer.log_index
],
lock: "FOR UPDATE"
)
query =
from(token_transfer in TokenTransfer,
select: map(token_transfer, [:transaction_hash, :log_index]),
inner_join: ordered_token_transfer in subquery(ordered_token_transfers),
on:
ordered_token_transfer.transaction_hash ==
token_transfer.transaction_hash and
ordered_token_transfer.log_index == token_transfer.log_index
)
try do
{_count, deleted_token_transfers} = repo.delete_all(query, timeout: timeout)
{:ok, deleted_token_transfers}
rescue
postgrex_error in Postgrex.Error ->
{:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}}
end
end
defp remove_nonconsensus_internal_transactions(repo, nonconsensus_block_numbers, %{timeout: timeout}) do
transaction_query =
from(transaction in Transaction,
where: transaction.block_number in ^nonconsensus_block_numbers,
select: map(transaction, [:hash]),
order_by: transaction.hash
)
ordered_internal_transactions =
from(internal_transaction in InternalTransaction,
inner_join: transaction in subquery(transaction_query),
on: internal_transaction.transaction_hash == transaction.hash,
select: map(internal_transaction, [:transaction_hash, :index]),
# Enforce InternalTransaction ShareLocks order (see docs: sharelocks.md)
order_by: [
internal_transaction.transaction_hash,
internal_transaction.index
],
lock: "FOR UPDATE OF i0"
)
query =
from(internal_transaction in InternalTransaction,
select: map(internal_transaction, [:transaction_hash, :index]),
inner_join: ordered_internal_transaction in subquery(ordered_internal_transactions),
on:
ordered_internal_transaction.transaction_hash == internal_transaction.transaction_hash and
ordered_internal_transaction.index == internal_transaction.index
)
try do
{_count, deleted_internal_transactions} = repo.delete_all(query, timeout: timeout)
{:ok, deleted_internal_transactions}
rescue
postgrex_error in Postgrex.Error ->
{:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}}
end
end
defp remove_nonconsensus_logs(repo, nonconsensus_block_numbers, %{timeout: timeout}) do
transaction_query =
from(transaction in Transaction,
where: transaction.block_number in ^nonconsensus_block_numbers,
select: map(transaction, [:hash]),
order_by: transaction.hash
)
ordered_logs =
from(log in Log,
inner_join: transaction in subquery(transaction_query),
on: log.transaction_hash == transaction.hash,
select: map(log, [:transaction_hash, :index]),
# Enforce Log ShareLocks order (see docs: sharelocks.md)
order_by: [
log.transaction_hash,
log.index
],
lock: "FOR UPDATE OF l0"
)
query =
from(log in Log,
select: map(log, [:transaction_hash, :index]),
inner_join: ordered_log in subquery(ordered_logs),
on: ordered_log.transaction_hash == log.transaction_hash and ordered_log.index == log.index
)
try do
{_count, deleted_logs} = repo.delete_all(query, timeout: timeout)
{:ok, deleted_logs}
rescue
postgrex_error in Postgrex.Error ->
{:error, %{exception: postgrex_error, block_numbers: nonconsensus_block_numbers}}
end
end
defp delete_address_token_balances(_, [], _), do: {:ok, []} defp delete_address_token_balances(_, [], _), do: {:ok, []}
defp delete_address_token_balances(repo, ordered_consensus_block_numbers, %{timeout: timeout}) do defp delete_address_token_balances(repo, ordered_consensus_block_numbers, %{timeout: timeout}) do

@ -26,7 +26,10 @@ defmodule Explorer.Chain.OrderedCache do
preload: [transaction: :hash] preload: [transaction: :hash]
``` ```
Additionally all of the options accepted by `ConCache.start_link/1` can be Additionally all of the options accepted by `ConCache.start_link/1` can be
provided as well. By default only `ttl_check_interval:` is set (to `false`). provided as well. Unless specified, only these values have defaults:
- `:ttl_check_interval` is set (to `false`).
- `:callback` is only set if `:ttl_check_interval` is not `false` to call the
`remove_deleted_from_index` function, that removes expired values from the index.
It's also possible, and advised, to override the implementation of the `c:prevails?/2` It's also possible, and advised, to override the implementation of the `c:prevails?/2`
and `c:element_to_id/1` callbacks. and `c:element_to_id/1` callbacks.
@ -131,10 +134,7 @@ defmodule Explorer.Chain.OrderedCache do
max_size = Keyword.get(opts, :max_size, 100) max_size = Keyword.get(opts, :max_size, 100)
preloads = Keyword.get(opts, :preloads) || Keyword.get_values(opts, :preload) preloads = Keyword.get(opts, :preloads) || Keyword.get_values(opts, :preload)
concache_params = concache_params = Keyword.drop(opts, [:ids_list_key, :max_size, :preloads, :preload])
opts
|> Keyword.drop([:ids_list_key, :max_size, :preloads, :preload])
|> Keyword.put_new(:ttl_check_interval, false)
# credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks # credo:disable-for-next-line Credo.Check.Refactor.LongQuoteBlocks
quote do quote do
@ -206,6 +206,19 @@ defmodule Explorer.Chain.OrderedCache do
### Updating function ### Updating function
def remove_deleted_from_index({:delete, _cache_pid, id}) do
# simply check with `ConCache.get` because it is faster
if Enum.member?(ids_list(), id) do
ConCache.update(cache_name(), ids_list_key(), fn ids ->
updated_list = List.delete(ids || [], id)
# ids_list is set to never expire
{:ok, %ConCache.Item{value: updated_list, ttl: :infinity}}
end)
end
end
def remove_deleted_from_index(_), do: nil
@impl OrderedCache @impl OrderedCache
def update(elements) when is_nil(elements), do: :ok def update(elements) when is_nil(elements), do: :ok
@ -217,7 +230,8 @@ defmodule Explorer.Chain.OrderedCache do
|> Enum.sort(&prevails?(&1, &2)) |> Enum.sort(&prevails?(&1, &2))
|> merge_and_update(ids || [], max_size()) |> merge_and_update(ids || [], max_size())
{:ok, updated_list} # ids_list is set to never expire
{:ok, %ConCache.Item{value: updated_list, ttl: :infinity}}
end) end)
end end
@ -308,7 +322,21 @@ defmodule Explorer.Chain.OrderedCache do
provided to this function will override the ones set by using the macro provided to this function will override the ones set by using the macro
""" """
def child_spec(params) do def child_spec(params) do
params = Keyword.merge(unquote(concache_params), params) # params specified in `use`
merged_params =
unquote(concache_params)
# params specified in `child_spec`
|> Keyword.merge(params)
# `:ttl_check_interval` needs to be specified, defaults to `false`
|> Keyword.put_new(:ttl_check_interval, false)
# if `:ttl_check_interval` is not `false` the expired values need to be
# removed from the cache's index
params =
case merged_params[:ttl_check_interval] do
false -> merged_params
_ -> Keyword.put_new(merged_params, :callback, &remove_deleted_from_index/1)
end
Supervisor.child_spec({ConCache, params}, id: child_id()) Supervisor.child_spec({ConCache, params}, id: child_id())
end end

@ -271,6 +271,45 @@ defmodule Explorer.Chain.SmartContract do
|> add_error(:contract_source_code, error_message(error)) |> add_error(:contract_source_code, error_message(error))
end end
def add_submitted_comment(code, inserted_at) when is_binary(code) do
code
|> String.split("\n")
|> add_submitted_comment(inserted_at)
|> Enum.join("\n")
end
def add_submitted_comment(contract_lines, inserted_at) when is_list(contract_lines) do
etherscan_index =
Enum.find_index(contract_lines, fn line ->
String.contains?(line, "Submitted for verification at Etherscan.io")
end)
blockscout_index =
Enum.find_index(contract_lines, fn line ->
String.contains?(line, "Submitted for verification at blockscout.com")
end)
cond do
etherscan_index && blockscout_index ->
List.replace_at(contract_lines, etherscan_index, "*")
etherscan_index && !blockscout_index ->
List.replace_at(
contract_lines,
etherscan_index,
"* Submitted for verification at blockscout.com on #{inserted_at}"
)
!etherscan_index && !blockscout_index ->
header = ["/**", "* Submitted for verification at blockscout.com on #{inserted_at}", "*/"]
header ++ contract_lines
true ->
contract_lines
end
end
defp upsert_contract_methods(%Ecto.Changeset{changes: %{abi: abi}} = changeset) do defp upsert_contract_methods(%Ecto.Changeset{changes: %{abi: abi}} = changeset) do
ContractMethod.upsert_from_abi(abi, get_field(changeset, :address_hash)) ContractMethod.upsert_from_abi(abi, get_field(changeset, :address_hash))

@ -3,18 +3,23 @@ defmodule Explorer.ChainSpec.Parity.Importer do
Imports data from parity chain spec. Imports data from parity chain spec.
""" """
require Logger
alias Explorer.{Chain, Repo} alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block.{EmissionReward, Range} alias Explorer.Chain.Block.{EmissionReward, Range}
alias Explorer.Chain.Hash.Address, as: AddressHash alias Explorer.Chain.Hash.Address, as: AddressHash
alias Explorer.Chain.Wei alias Explorer.Chain.Wei
alias Explorer.ChainSpec.GenesisData
alias Explorer.ChainSpec.POA.Importer, as: PoaEmissionImporter
@max_block_number :infinity @max_block_number :infinity
def import_emission_rewards(chain_spec) do def import_emission_rewards(chain_spec) do
rewards = emission_rewards(chain_spec) if Application.get_env(:explorer, GenesisData)[:emission_format] == "POA" do
PoaEmissionImporter.import_emission_rewards()
{_, nil} = Repo.delete_all(EmissionReward) else
{_, nil} = Repo.insert_all(EmissionReward, rewards) import_rewards_from_chain_spec(chain_spec)
end
end end
def import_genesis_coin_balances(chain_spec) do def import_genesis_coin_balances(chain_spec) do
@ -38,18 +43,37 @@ defmodule Explorer.ChainSpec.Parity.Importer do
Chain.import(params) Chain.import(params)
end end
defp import_rewards_from_chain_spec(chain_spec) do
rewards = emission_rewards(chain_spec)
{_, nil} = Repo.delete_all(EmissionReward)
{_, nil} = Repo.insert_all(EmissionReward, rewards)
end
def genesis_coin_balances(chain_spec) do def genesis_coin_balances(chain_spec) do
accounts = chain_spec["accounts"] accounts = chain_spec["accounts"]
if accounts do
parse_accounts(accounts) parse_accounts(accounts)
else
Logger.warn(fn -> "No accounts are defined in chain spec" end)
[]
end
end end
def emission_rewards(chain_spec) do def emission_rewards(chain_spec) do
rewards = chain_spec["engine"]["Ethash"]["params"]["blockReward"] rewards = chain_spec["engine"]["Ethash"]["params"]["blockReward"]
if rewards do
rewards rewards
|> parse_hex_numbers() |> parse_hex_numbers()
|> format_ranges() |> format_ranges()
else
Logger.warn(fn -> "No rewards are defined in chain spec" end)
[]
end
end end
defp parse_accounts(accounts) do defp parse_accounts(accounts) do
@ -59,7 +83,7 @@ defmodule Explorer.ChainSpec.Parity.Importer do
end) end)
|> Stream.map(fn {address, %{"balance" => value}} -> |> Stream.map(fn {address, %{"balance" => value}} ->
{:ok, address_hash} = AddressHash.cast(address) {:ok, address_hash} = AddressHash.cast(address)
balance = parse_hex_number(value) balance = parse_number(value)
%{address_hash: address_hash, value: balance} %{address_hash: address_hash, value: balance}
end) end)
@ -92,16 +116,22 @@ defmodule Explorer.ChainSpec.Parity.Importer do
defp parse_hex_numbers(rewards) do defp parse_hex_numbers(rewards) do
Enum.map(rewards, fn {hex_block_number, hex_reward} -> Enum.map(rewards, fn {hex_block_number, hex_reward} ->
block_number = parse_hex_number(hex_block_number) block_number = parse_number(hex_block_number)
{:ok, reward} = hex_reward |> parse_hex_number() |> Wei.cast() {:ok, reward} = hex_reward |> parse_number() |> Wei.cast()
{block_number, reward} {block_number, reward}
end) end)
end end
defp parse_hex_number("0x" <> hex_number) do defp parse_number("0x" <> hex_number) do
{number, ""} = Integer.parse(hex_number, 16) {number, ""} = Integer.parse(hex_number, 16)
number number
end end
defp parse_number(string_number) do
{number, ""} = Integer.parse(string_number, 10)
number
end
end end

@ -0,0 +1,89 @@
defmodule Explorer.ChainSpec.POA.Importer do
@moduledoc """
Imports emission reward range for POA chain.
"""
require Logger
alias Explorer.Chain.Wei
alias Explorer.Repo
alias Explorer.SmartContract.Reader
alias Explorer.Chain.Block.{EmissionReward, Range}
alias Explorer.ChainSpec.GenesisData
@block_reward_amount_abi %{
"type" => "function",
"stateMutability" => "view",
"payable" => false,
"outputs" => [%{"type" => "uint256", "name" => ""}],
"name" => "blockRewardAmount",
"inputs" => [],
"constant" => true
}
@block_reward_amount_params %{"blockRewardAmount" => []}
@emission_funds_amount_abi %{
"type" => "function",
"stateMutability" => "view",
"payable" => false,
"outputs" => [%{"type" => "uint256", "name" => ""}],
"name" => "emissionFundsAmount",
"inputs" => [],
"constant" => true
}
@emission_funds_amount_params %{"emissionFundsAmount" => []}
@emission_funds_block_start 5_098_087
def import_emission_rewards do
if is_nil(rewards_contract_address()) do
Logger.warn(fn -> "No rewards contract address is defined" end)
else
block_reward = block_reward_amount()
emission_funds = emission_funds_amount()
rewards = [
%{
block_range: %Range{from: 0, to: @emission_funds_block_start},
reward: %Wei{value: block_reward}
},
%{
block_range: %Range{from: @emission_funds_block_start + 1, to: :infinity},
reward: %Wei{value: Decimal.add(block_reward, emission_funds)}
}
]
{_, nil} = Repo.delete_all(EmissionReward)
{_, nil} = Repo.insert_all(EmissionReward, rewards)
end
end
def block_reward_amount do
call_contract(rewards_contract_address(), @block_reward_amount_abi, @block_reward_amount_params)
end
def emission_funds_amount do
call_contract(rewards_contract_address(), @emission_funds_amount_abi, @emission_funds_amount_params)
end
defp rewards_contract_address do
Application.get_env(:explorer, GenesisData)[:rewards_contract_address]
end
defp call_contract(address, abi, params) do
abi = [abi]
method_name =
params
|> Enum.map(fn {key, _value} -> key end)
|> List.first()
Reader.query_contract(address, abi, params)
value =
case Reader.query_contract(address, abi, params) do
%{^method_name => {:ok, [result]}} -> result
_ -> 0
end
Decimal.new(value)
end
end

@ -44,15 +44,41 @@ defmodule Explorer.ExchangeRates.Source.CoinGecko do
@impl Source @impl Source
def source_url do def source_url do
"#{base_url()}/coins/#{coin_id()}" {:ok, id} = coin_id()
"#{base_url()}/coins/#{id}"
end end
defp base_url do defp base_url do
config(:base_url) || "https://api.coingecko.com/api/v3" config(:base_url) || "https://api.coingecko.com/api/v3"
end end
defp coin_id do def coin_id do
Application.get_env(:explorer, __MODULE__)[:coin_id] url = "#{base_url()}/coins/list"
symbol = String.downcase(Explorer.coin())
case HTTPoison.get(url, headers()) do
{:ok, %Response{body: body, status_code: 200}} ->
data = decode_json(body)
symbol_data =
Enum.find(data, fn item ->
item["symbol"] == symbol
end)
if symbol_data do
{:ok, symbol_data["id"]}
else
{:error, :not_found}
end
{:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 ->
{:error, decode_json(body)["error"]}
{:error, %Error{reason: reason}} ->
{:error, reason}
end
end end
defp get_btc_price(currency \\ "usd") do defp get_btc_price(currency \\ "usd") do

@ -0,0 +1,7 @@
defmodule Explorer.Repo.Migrations.CreateIndexesForBlockNumberInTokenTransfersAndTransactions do
use Ecto.Migration
def change do
create_if_not_exists(index(:token_transfers, [:block_number]))
end
end

@ -11,7 +11,7 @@ defmodule Explorer.Chain.Cache.BlockNumberTest do
end) end)
end end
describe "get_max/1" do describe "get_max/0" do
test "returns max number" do test "returns max number" do
insert(:block, number: 5) insert(:block, number: 5)
@ -19,7 +19,7 @@ defmodule Explorer.Chain.Cache.BlockNumberTest do
end end
end end
describe "get_min/1" do describe "get_min/0" do
test "returns min number" do test "returns min number" do
insert(:block, number: 2) insert(:block, number: 2)
@ -27,7 +27,7 @@ defmodule Explorer.Chain.Cache.BlockNumberTest do
end end
end end
describe "get_all/1" do describe "get_all/0" do
test "returns min and max number" do test "returns min and max number" do
insert(:block, number: 6) insert(:block, number: 6)

@ -7,13 +7,14 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
alias Ecto.Multi alias Ecto.Multi
alias Explorer.Chain.Import.Runner.{Blocks, Transactions} alias Explorer.Chain.Import.Runner.{Blocks, Transactions}
alias Explorer.Chain.{Address, Block, Transaction} alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Transaction, TokenTransfer}
alias Explorer.Chain alias Explorer.Chain
alias Explorer.Repo alias Explorer.Repo
describe "run/1" do describe "run/1" do
setup do setup do
block = insert(:block, consensus: true) miner = insert(:address)
block = params_for(:block, consensus: true, miner_hash: miner.hash)
timestamp = DateTime.utc_now() timestamp = DateTime.utc_now()
options = %{timestamps: %{inserted_at: timestamp, updated_at: timestamp}} options = %{timestamps: %{inserted_at: timestamp, updated_at: timestamp}}
@ -22,9 +23,11 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
test "derive_transaction_forks replaces hash on conflicting (uncle_hash, index)", %{ test "derive_transaction_forks replaces hash on conflicting (uncle_hash, index)", %{
consensus_block: %Block{hash: block_hash, miner_hash: miner_hash, number: block_number} = consensus_block, consensus_block: %{hash: block_hash, miner_hash: miner_hash, number: block_number},
options: options options: options
} do } do
consensus_block = insert(:block, %{hash: block_hash, number: block_number})
transaction = transaction =
:transaction :transaction
|> insert() |> insert()
@ -81,7 +84,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
test "delete_address_current_token_balances deletes rows with matching block number when consensus is true", test "delete_address_current_token_balances deletes rows with matching block number when consensus is true",
%{consensus_block: %Block{number: block_number} = block, options: options} do %{consensus_block: %{number: block_number} = block, options: options} do
%Address.CurrentTokenBalance{address_hash: address_hash, token_contract_address_hash: token_contract_address_hash} = %Address.CurrentTokenBalance{address_hash: address_hash, token_contract_address_hash: token_contract_address_hash} =
insert(:address_current_token_balance, block_number: block_number) insert(:address_current_token_balance, block_number: block_number)
@ -98,7 +101,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
test "delete_address_current_token_balances does not delete rows with matching block number when consensus is false", test "delete_address_current_token_balances does not delete rows with matching block number when consensus is false",
%{consensus_block: %Block{number: block_number} = block, options: options} do %{consensus_block: %{number: block_number} = block, options: options} do
%Address.CurrentTokenBalance{} = insert(:address_current_token_balance, block_number: block_number) %Address.CurrentTokenBalance{} = insert(:address_current_token_balance, block_number: block_number)
count = 1 count = 1
@ -113,8 +116,93 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
assert count(Address.CurrentTokenBalance) == count assert count(Address.CurrentTokenBalance) == count
end end
test "remove_nonconsensus_data deletes token transfer rows with matching block number when new consensus block is inserted",
%{consensus_block: %{number: block_number} = block, options: options} do
insert(:block, number: block_number, consensus: true)
%TokenTransfer{transaction_hash: transaction_hash, log_index: log_index} =
insert(:token_transfer, block_number: block_number, transaction: insert(:transaction))
assert count(TokenTransfer) == 1
assert {:ok,
%{
remove_nonconsensus_data: %{
token_transfers: [
%{transaction_hash: ^transaction_hash, log_index: ^log_index}
]
}
}} = run_block_consensus_change(block, true, options)
assert count(TokenTransfer) == 0
end
test "remove_nonconsensus_data does not delete token transfer rows with matching block number when new consensus block wasn't inserted",
%{consensus_block: %{number: block_number} = block, options: options} do
insert(:token_transfer, block_number: block_number, transaction: insert(:transaction))
count = 1
assert count(TokenTransfer) == count
assert {:ok,
%{
remove_nonconsensus_data: %{
token_transfers: []
}
}} = run_block_consensus_change(block, false, options)
assert count(TokenTransfer) == count
end
test "remove_nonconsensus_data deletes nonconsensus logs", %{
consensus_block: %{number: block_number} = block,
options: options
} do
old_block = insert(:block, number: block_number, consensus: true)
forked_transaction = :transaction |> insert() |> with_block(old_block)
%Log{transaction_hash: hash, index: index} = insert(:log, transaction: forked_transaction)
assert count(Log) == 1
assert {:ok,
%{
remove_nonconsensus_data: %{
logs: [
%{transaction_hash: ^hash, index: ^index}
]
}
}} = run_block_consensus_change(block, true, options)
assert count(Log) == 0
end
test "remove_nonconsensus_data deletes nonconsensus internal transactions", %{
consensus_block: %{number: block_number} = block,
options: options
} do
old_block = insert(:block, number: block_number, consensus: true)
forked_transaction = :transaction |> insert() |> with_block(old_block)
%InternalTransaction{index: index, transaction_hash: hash} =
insert(:internal_transaction, index: 0, transaction: forked_transaction)
assert count(InternalTransaction) == 1
assert {:ok,
%{
remove_nonconsensus_data: %{
internal_transactions: [
%{transaction_hash: ^hash, index: ^index}
]
}
}} = run_block_consensus_change(block, true, options)
assert count(InternalTransaction) == 0
end
test "derive_address_current_token_balances inserts rows if there is an address_token_balance left for the rows deleted by delete_address_current_token_balances", test "derive_address_current_token_balances inserts rows if there is an address_token_balance left for the rows deleted by delete_address_current_token_balances",
%{consensus_block: %Block{number: block_number} = block, options: options} do %{consensus_block: %{number: block_number} = block, options: options} do
token = insert(:token) token = insert(:token)
token_contract_address_hash = token.contract_address_hash token_contract_address_hash = token.contract_address_hash
@ -172,7 +260,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
test "a non-holder reverting to a holder increases the holder_count", test "a non-holder reverting to a holder increases the holder_count",
%{consensus_block: %Block{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do %{consensus_block: %{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do
token = insert(:token) token = insert(:token)
token_contract_address_hash = token.contract_address_hash token_contract_address_hash = token.contract_address_hash
@ -204,7 +292,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
test "a holder reverting to a non-holder decreases the holder_count", test "a holder reverting to a non-holder decreases the holder_count",
%{consensus_block: %Block{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do %{consensus_block: %{hash: block_hash, miner_hash: miner_hash, number: block_number}, options: options} do
token = insert(:token) token = insert(:token)
token_contract_address_hash = token.contract_address_hash token_contract_address_hash = token.contract_address_hash
@ -236,7 +324,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
test "a non-holder becoming and a holder becoming while a holder becomes a non-holder cancels out and holder_count does not change", test "a non-holder becoming and a holder becoming while a holder becomes a non-holder cancels out and holder_count does not change",
%{consensus_block: %Block{number: block_number} = block, options: options} do %{consensus_block: %{number: block_number} = block, options: options} do
token = insert(:token) token = insert(:token)
token_contract_address_hash = token.contract_address_hash token_contract_address_hash = token.contract_address_hash
@ -262,7 +350,8 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
# Regression test for https://github.com/poanetwork/blockscout/issues/1644 # Regression test for https://github.com/poanetwork/blockscout/issues/1644
test "discards neighbouring blocks if they aren't related to the current one because of reorg and/or import timeout", test "discards neighbouring blocks if they aren't related to the current one because of reorg and/or import timeout",
%{consensus_block: %Block{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do %{consensus_block: %{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do
insert(:block, %{number: block_number, hash: block_hash})
old_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1) old_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1)
new_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1) new_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1)
@ -286,7 +375,8 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
# Regression test for https://github.com/poanetwork/blockscout/issues/1911 # Regression test for https://github.com/poanetwork/blockscout/issues/1911
test "forces block refetch if transaction is re-collated in a different block", test "forces block refetch if transaction is re-collated in a different block",
%{consensus_block: %Block{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do %{consensus_block: %{number: block_number, hash: block_hash, miner_hash: miner_hash}, options: options} do
insert(:block, %{number: block_number, hash: block_hash})
new_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1) new_block1 = params_for(:block, miner_hash: miner_hash, parent_hash: block_hash, number: block_number + 1)
new_block2 = params_for(:block, miner_hash: miner_hash, parent_hash: new_block1.hash, number: block_number + 2) new_block2 = params_for(:block, miner_hash: miner_hash, parent_hash: new_block1.hash, number: block_number + 2)
@ -365,7 +455,7 @@ defmodule Explorer.Chain.Import.Runner.BlocksTest do
end end
defp run_block_consensus_change( defp run_block_consensus_change(
%Block{hash: block_hash, miner_hash: miner_hash, number: block_number}, %{hash: block_hash, miner_hash: miner_hash, number: block_number},
consensus, consensus,
options options
) do ) do

@ -18,6 +18,46 @@ defmodule Explorer.ExchangeRates.Source.CoinGeckoTest do
} }
""" """
@coins_list """
[
{
"id": "poa-network",
"symbol": "poa",
"name": "POA Network"
},
{
"id": "poc-chain",
"symbol": "pocc",
"name": "POC Chain"
},
{
"id": "pocket-arena",
"symbol": "poc",
"name": "Pocket Arena"
},
{
"id": "ethereum",
"symbol": "eth",
"name": "Ethereum"
},
{
"id": "rootstock",
"symbol": "rbtc",
"name": "Rootstock RSK"
},
{
"id": "dai",
"symbol": "dai",
"name": "Dai"
},
{
"id": "callisto",
"symbol": "clo",
"name": "Callisto Network"
}
]
"""
describe "format_data/1" do describe "format_data/1" do
setup do setup do
bypass = Bypass.open() bypass = Bypass.open()
@ -62,4 +102,65 @@ defmodule Explorer.ExchangeRates.Source.CoinGeckoTest do
assert [] = CoinGecko.format_data(bad_data) assert [] = CoinGecko.format_data(bad_data)
end end
end end
describe "coin_id/0" do
setup do
bypass = Bypass.open()
Application.put_env(:explorer, CoinGecko, base_url: "http://localhost:#{bypass.port}")
on_exit(fn ->
Application.put_env(:explorer, :coin, "POA")
end)
{:ok, bypass: bypass}
end
test "fetches poa coin id by default", %{bypass: bypass} do
Bypass.expect(bypass, "GET", "/coins/list", fn conn ->
Conn.resp(conn, 200, @coins_list)
end)
assert CoinGecko.coin_id() == {:ok, "poa-network"}
end
test "fetches eth coin id", %{bypass: bypass} do
Application.put_env(:explorer, :coin, "ETH")
Bypass.expect(bypass, "GET", "/coins/list", fn conn ->
Conn.resp(conn, 200, @coins_list)
end)
assert CoinGecko.coin_id() == {:ok, "ethereum"}
end
test "fetches rbtc coin id", %{bypass: bypass} do
Application.put_env(:explorer, :coin, "RBTC")
Bypass.expect(bypass, "GET", "/coins/list", fn conn ->
Conn.resp(conn, 200, @coins_list)
end)
assert CoinGecko.coin_id() == {:ok, "rootstock"}
end
test "fetches dai coin id", %{bypass: bypass} do
Application.put_env(:explorer, :coin, "DAI")
Bypass.expect(bypass, "GET", "/coins/list", fn conn ->
Conn.resp(conn, 200, @coins_list)
end)
assert CoinGecko.coin_id() == {:ok, "dai"}
end
test "fetches callisto coin id", %{bypass: bypass} do
Application.put_env(:explorer, :coin, "CLO")
Bypass.expect(bypass, "GET", "/coins/list", fn conn ->
Conn.resp(conn, 200, @coins_list)
end)
assert CoinGecko.coin_id() == {:ok, "callisto"}
end
end
end end

@ -84,18 +84,6 @@ defmodule Indexer.Block.Fetcher.ReceiptsTest do
"transactionIndex" => "0x0", "transactionIndex" => "0x0",
"transactionLogIndex" => "0x0", "transactionLogIndex" => "0x0",
"type" => "mined" "type" => "mined"
},
%{
"address" => "0x8bf38d4764929064f2d4d3a56520a76ab3df415c",
"blockHash" => nil,
"blockNumber" => nil,
"data" => "0x000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef",
"logIndex" => "0x1",
"topics" => ["0x600bcf04a13e752d1e3670a5a9f1c21177ca2a93c6f5391d4f1298d098097c22"],
"transactionHash" => "0x53bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5",
"transactionIndex" => "0x0",
"transactionLogIndex" => "0x0",
"type" => "pending"
} }
], ],
"logsBloom" => "logsBloom" =>
@ -158,8 +146,6 @@ defmodule Indexer.Block.Fetcher.ReceiptsTest do
log[:transaction_hash] == "0x43bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5" && log[:transaction_hash] == "0x43bd884872de3e488692881baeec262e7b95234d3965248c39fe992fffd433e5" &&
log[:block_number] == 46147 log[:block_number] == 46147
end) end)
refute Enum.find(logs, fn log -> log[:type] == "pending" end)
end end
end end
end end

@ -52,10 +52,11 @@ $ export NETWORK=POA
| `TXS_COUNT_CACHE_PERIOD` | | Interval in seconds to restart the task, which calculates the total txs count. | 60 * 60 * 2 | v1.3.9+ | | | | `TXS_COUNT_CACHE_PERIOD` | | Interval in seconds to restart the task, which calculates the total txs count. | 60 * 60 * 2 | v1.3.9+ | | |
| `ADDRESS_WITH_BALANCES` <br /> `_UPDATE_INTERVAL`| | Interval in seconds to restart the task, which calculates addresses with balances. | 30 * 60 | v1.3.9+ | | | | `ADDRESS_WITH_BALANCES` <br /> `_UPDATE_INTERVAL`| | Interval in seconds to restart the task, which calculates addresses with balances. | 30 * 60 | v1.3.9+ | | |
| `LINK_TO_OTHER_EXPLORERS` | | true/false. If true, links to other explorers are added in the footer | (empty) | v1.3.0+ | | | | `LINK_TO_OTHER_EXPLORERS` | | true/false. If true, links to other explorers are added in the footer | (empty) | v1.3.0+ | | |
| `COINMARKETCAP_PAGES` | | the number of pages on coinmarketcap to list in order to find token's price | 10 | v1.3.10+ | | master | | `COINMARKETCAP_PAGES` | | the number of pages on coinmarketcap to list in order to find token's price | 10 | v1.3.10+ | | v2.0.4 |
| `SUPPORTED_CHAINS` | | Array of supported chains that displays in the footer and in the chains dropdown. This var was introduced in this PR [#1900](https://github.com/poanetwork/blockscout/pull/1900) and looks like an array of JSON objects. | (empty) | v2.0.0+ | | | | `SUPPORTED_CHAINS` | | Array of supported chains that displays in the footer and in the chains dropdown. This var was introduced in this PR [#1900](https://github.com/poanetwork/blockscout/pull/1900) and looks like an array of JSON objects. | (empty) | v2.0.0+ | | |
| `BLOCK_COUNT_CACHE_PERIOD ` | | time to live of cache in seconds. This var was introduced in [#1876](https://github.com/poanetwork/blockscout/pull/1876) | 600 | v2.0.0+ | | | | `BLOCK_COUNT_CACHE_PERIOD ` | | time to live of cache in seconds. This var was introduced in [#1876](https://github.com/poanetwork/blockscout/pull/1876) | 600 | v2.0.0+ | | |
| `ALLOWED_EVM_VERSIONS ` | | the comma-separated list of allowed EVM versions for contracts verification. This var was introduced in [#1964](https://github.com/poanetwork/blockscout/pull/1964) | "homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg" | v2.0.0+ | | | | `ALLOWED_EVM_VERSIONS ` | | the comma-separated list of allowed EVM versions for contracts verification. This var was introduced in [#1964](https://github.com/poanetwork/blockscout/pull/1964) | "homestead, tangerineWhistle, spuriousDragon, byzantium, constantinople, petersburg" | v2.0.0+ | | |
| `UNCLES_IN_AVERAGE_BLOCK_TIME` | Include or exclude nonconsensus blocks in avg block time calculation. Exclude if `false`. | false | v2.0.1+ | | |
| `AVERAGE_BLOCK_CACHE_PERIOD` | | Update of average block cache, in seconds | 30 minutes | v2.0.2+ | | | `AVERAGE_BLOCK_CACHE_PERIOD` | | Update of average block cache, in seconds | 30 minutes | v2.0.2+ | |
| `MARKET_HISTORY_CACHE_PERIOD` | | Update of market history cache, in seconds | 6 hours | v2.0.2+ | | | `MARKET_HISTORY_CACHE_PERIOD` | | Update of market history cache, in seconds | 6 hours | v2.0.2+ | |
| `DISABLE_WEBAPP` | | If `true`, endpoints to webapp are hidden (compile-time) | `false` | v2.0.3+ | :white_check_mark: | | | `DISABLE_WEBAPP` | | If `true`, endpoints to webapp are hidden (compile-time) | `false` | v2.0.3+ | :white_check_mark: | |
@ -64,5 +65,7 @@ $ export NETWORK=POA
| `DISABLE_INDEXER` | | If `true`, indexer application doesn't run | `false` | v2.0.3+ | :white_check_mark: | | | `DISABLE_INDEXER` | | If `true`, indexer application doesn't run | `false` | v2.0.3+ | :white_check_mark: | |
| `WEBAPP_URL` | | Link to web application instance, e.g. `http://host/path` | (empty) | v2.0.3+ | | | | `WEBAPP_URL` | | Link to web application instance, e.g. `http://host/path` | (empty) | v2.0.3+ | | |
| `API_URL` | | Link to API instance, e.g. `http://host/path` | (empty) | v2.0.3+ | | | | `API_URL` | | Link to API instance, e.g. `http://host/path` | (empty) | v2.0.3+ | | |
| `CHAIN_SPEC_PATH` | | Chain specification path (absolute file system path or url) to import block emission reward ranges and genesis account balances from | (empty) | master | | | | `CHAIN_SPEC_PATH` | | Chain specification path (absolute file system path or url) to import block emission reward ranges and genesis account balances from | (empty) | v2.0.4+ | | |
| `COIN_GECKO_ID` | | CoinGecko coin id required for fetching an exchange rate | poa-network | master | | | | `COIN_GECKO_ID` | | CoinGecko coin id required for fetching an exchange rate | poa-network | v2.0.4+ | | master |
| `EMISSION_FORMAT` | | Should be set to `POA` if you have block emission indentical to POA Network. This env var is used only if `CHAIN_SPEC_PATH` is set | `STANDARD` | v2.0.4+ | | |
| `REWARDS_CONTRACT_ADDRESS` | | Emission rewards contract address. This env var is used only if `EMISSION_FORMAT` is set to `POA` | `0xeca443e8e1ab29971a45a9c57a6a9875701698a5` | v2.0.4+ | | |

Loading…
Cancel
Save