Merge branch 'master' into ab-add-new-fields-for-contract-verification

pull/2235/head
Ayrat Badykov 6 years ago committed by GitHub
commit 4c5ce5b68c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      CHANGELOG.md
  2. 4
      apps/block_scout_web/assets/css/app.scss
  3. 13
      apps/block_scout_web/assets/css/components/_navbar.scss
  4. 334
      apps/block_scout_web/assets/css/components/_network-selector.scss
  5. 49
      apps/block_scout_web/assets/css/components/_radio.scss
  6. 49
      apps/block_scout_web/assets/css/components/_transaction.scss
  7. 3
      apps/block_scout_web/assets/js/app.js
  8. 8
      apps/block_scout_web/assets/js/lib/async_listing_load.js
  9. 77
      apps/block_scout_web/assets/js/lib/network_selector.js
  10. 58
      apps/block_scout_web/assets/js/pages/favorites.js
  11. 21
      apps/block_scout_web/assets/js/pages/network-search.js
  12. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/aerum-mainnet.png
  13. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/callisto-mainnet.png
  14. 7
      apps/block_scout_web/assets/static/images/network-selector-icons/callisto.svg
  15. 4
      apps/block_scout_web/assets/static/images/network-selector-icons/core.svg
  16. 33
      apps/block_scout_web/assets/static/images/network-selector-icons/dai.svg
  17. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-classic.png
  18. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-mainnet.png
  19. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/goerli-testnet.png
  20. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/kovan-testnet.png
  21. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/poa-core.png
  22. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/poa-sokol.png
  23. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby-testnet.png
  24. 15
      apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby.svg
  25. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/ropsten-testnet.png
  26. 4
      apps/block_scout_web/assets/static/images/network-selector-icons/ropsten.svg
  27. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/rsk-mainnet.png
  28. 4
      apps/block_scout_web/assets/static/images/network-selector-icons/sokol.svg
  29. BIN
      apps/block_scout_web/assets/static/images/network-selector-icons/xdai-chain.png
  30. 2
      apps/block_scout_web/config/config.exs
  31. 41
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  32. 4
      apps/block_scout_web/lib/block_scout_web/router.ex
  33. 4
      apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex
  34. 13
      apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
  35. 12
      apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex
  36. 15
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
  37. 4
      apps/block_scout_web/lib/block_scout_web/templates/api_docs/eth_rpc.html.eex
  38. 2
      apps/block_scout_web/lib/block_scout_web/templates/api_docs/index.html.eex
  39. 53
      apps/block_scout_web/lib/block_scout_web/templates/layout/_network_selector.html.eex
  40. 25
      apps/block_scout_web/lib/block_scout_web/templates/layout/_network_selector_item.html.eex
  41. 17
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  42. 13
      apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex
  43. 12
      apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
  44. 10
      apps/block_scout_web/lib/block_scout_web/views/api_docs_view.ex
  45. 10
      apps/block_scout_web/lib/block_scout_web/views/layout_view.ex
  46. 15
      apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex
  47. 85
      apps/block_scout_web/priv/gettext/default.pot
  48. 91
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  49. 36
      apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
  50. 33
      apps/explorer/lib/explorer/chain.ex
  51. 119
      apps/explorer/lib/explorer/chain/address_token_transfer_csv_exporter.ex
  52. 139
      apps/explorer/lib/explorer/chain/address_transaction_csv_exporter.ex
  53. 11
      apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
  54. 7
      apps/explorer/lib/explorer/smart_contract/verifier.ex
  55. 8
      apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex
  56. 3
      apps/explorer/mix.exs
  57. 5
      apps/explorer/priv/compile_solc.js
  58. 72
      apps/explorer/test/explorer/chain/address_token_transfer_csv_exporter_test.exs
  59. 105
      apps/explorer/test/explorer/chain/address_transaction_csv_exporter_test.exs
  60. 4
      apps/explorer/test/explorer/chain_test.exs
  61. 14
      apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
  62. 32
      apps/explorer/test/explorer/smart_contract/verifier_test.exs
  63. 3874
      apps/explorer/test/support/fixture/smart_contract/large_smart_contract.sol
  64. 76
      apps/explorer/test/support/fixture/smart_contract/solidity_0.5.9_smart_contract.sol
  65. 2
      apps/indexer/mix.exs
  66. 2
      bin/install_chrome_headless.sh
  67. 2
      mix.lock

@ -7,8 +7,15 @@
- [#2191](https://github.com/poanetwork/blockscout/pull/2191) - allow to configure token metadata update interval
- [#2146](https://github.com/poanetwork/blockscout/pull/2146) - feat: add eth_getLogs rpc endpoint
- [#2235](https://github.com/poanetwork/blockscout/pull/2235) - save and show additional validation fields to smart contract
- [#2190](https://github.com/poanetwork/blockscout/pull/2190) - show all token transfers
- [#2193](https://github.com/poanetwork/blockscout/pull/2193) - feat: add BLOCKSCOUT_HOST, and use it in API docs
### Fixes
- [#2263](https://github.com/poanetwork/blockscout/pull/2263) - added an ability to close network selector on outside click
- [#2257](https://github.com/poanetwork/blockscout/pull/2257) - 'download csv' button added to different tabs
- [#2242](https://github.com/poanetwork/blockscout/pull/2242) - added styles for 'download csv' button
- [#2261](https://github.com/poanetwork/blockscout/pull/2261) - header logo aligned to the center properly
- [#2254](https://github.com/poanetwork/blockscout/pull/2254) - search length issue, tile link wrapping issue
- [#2238](https://github.com/poanetwork/blockscout/pull/2238) - header content alignment issue, hide navbar on outside click
- [#2229](https://github.com/poanetwork/blockscout/pull/2229) - gap issue between qr and copy button in token transfers, top cards width and height issue
- [#2201](https://github.com/poanetwork/blockscout/pull/2201) - footer columns fix
@ -46,17 +53,21 @@
- [#2173](https://github.com/poanetwork/blockscout/pull/2173) - handle correctly empty transactions
- [#2174](https://github.com/poanetwork/blockscout/pull/2174) - fix reward channel joining
- [#2186](https://github.com/poanetwork/blockscout/pull/2186) - fix net version test
- [#2167](https://github.com/poanetwork/blockscout/pull/2168) - feat: document eth rpc api mimicking endpoints
- [#2167](https://github.com/poanetwork/blockscout/pull/2167) - feat: document eth rpc api mimicking endpoints
- [#2225](https://github.com/poanetwork/blockscout/pull/2225) - fix metadata decoding in Solidity 0.5.9 smart contract verification
- [#2204](https://github.com/poanetwork/blockscout/pull/2204) - fix large contract verification
### Chore
- [#2127](https://github.com/poanetwork/blockscout/pull/2127) - use previouse chromedriver version
- [#2118](https://github.com/poanetwork/blockscout/pull/2118) - show only the last decompiled contract
- [#2256](https://github.com/poanetwork/blockscout/pull/2256) - use the latest version of chromedriver
### Chore
## 2.0.0-beta
### Features
- [#2044](https://github.com/poanetwork/blockscout/pull/2044) - New network selector.
- [#2091](https://github.com/poanetwork/blockscout/pull/2091) - Added "Question" modal.
- [#1963](https://github.com/poanetwork/blockscout/pull/1963), [#1959](https://github.com/poanetwork/blockscout/pull/1959), [#1948](https://github.com/poanetwork/blockscout/pull/1948), [#1936](https://github.com/poanetwork/blockscout/pull/1936), [#1925](https://github.com/poanetwork/blockscout/pull/1925), [#1922](https://github.com/poanetwork/blockscout/pull/1922), [#1903](https://github.com/poanetwork/blockscout/pull/1903), [#1874](https://github.com/poanetwork/blockscout/pull/1874), [#1895](https://github.com/poanetwork/blockscout/pull/1895), [#2031](https://github.com/poanetwork/blockscout/pull/2031), [#2073](https://github.com/poanetwork/blockscout/pull/2073), [#2074](https://github.com/poanetwork/blockscout/pull/2074), - added new themes and logos for poa, eth, rinkeby, goerli, ropsten, kovan, sokol, xdai, etc, rsk and default theme
- [#1726](https://github.com/poanetwork/blockscout/pull/2071) - Updated styles for the new smart contract page.
@ -82,6 +93,9 @@
- [#2100](https://github.com/poanetwork/blockscout/pull/2100) - feat: eth_get_balance rpc endpoint
### Fixes
- [#2228](https://github.com/poanetwork/blockscout/pull/2228) - favorites duplication issues, active radio issue
- [#2207](https://github.com/poanetwork/blockscout/pull/2207) - new 'download csv' button design
- [#2206](https://github.com/poanetwork/blockscout/pull/2206) - added styles for 'Download All Transactions as CSV' button
- [#2099](https://github.com/poanetwork/blockscout/pull/2099) - logs search input width
- [#2098](https://github.com/poanetwork/blockscout/pull/2098) - nav dropdown issue, logo size issue
- [#2082](https://github.com/poanetwork/blockscout/pull/2082) - dropdown styles, tooltip gap fix, 404 page added

@ -123,8 +123,8 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "components/verify_other_explorers";
@import "components/errors";
@import "components/log-search";
@import "components/radio";
@import "components/network-selector";
@import "components/new_smart_contract";
@import "components/radio_big";
@import "components/btn_no_border";

@ -151,19 +151,13 @@ $navbar-logo-width: auto !default;
}
@include media-breakpoint-up(xl) {
width: 280px;
width: 340px;
}
@media (min-width: 1366px) {
width: 330px;
width: 500px;
}
@media (min-width: 1440px) {
width: 380px;
}
@media (min-width: 1580px) {
width: 430px;
}
@media (min-width: 1800px) {
width: 520px;
width: 580px;
}
}
.input-group-append {
@ -223,6 +217,7 @@ $navbar-logo-width: auto !default;
.navbar-brand {
margin-left: 0;
flex-shrink: 1;
display: inline-flex;
.navbar-logo {
max-width: 100%;
}

@ -0,0 +1,334 @@
$network-selector-overlay-background: $modal-overlay-color !default;
$network-selector-close-color: $primary !default;
$network-selector-horizontal-padding: 28px;
$btn-network-selector-load-more-background: #fff !default;
$btn-network-selector-load-more-color: $primary !default;
$network-selector-search-input-color: #a3a9b5 !default;
$network-selector-tab-active-border-color: $primary !default;
$network-selector-item-icon-dimensions: 30px !default;
.network-selector-visible {
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
}
.network-selector-overlay {
background-color: rgba($network-selector-overlay-background, 0.9);
bottom: 0;
display: none;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 123;
}
.network-selector-overlay-close {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.network-selector-wrapper {
display: flex;
height: 100%;
width: 100%;
}
.network-selector {
background-color: #fff;
display: flex;
flex-direction: column;
flex-grow: 1;
flex-shrink: 1;
margin-left: auto;
max-width: 398px;
min-width: 0;
padding-top: 28px;
position: relative;
transition: right 0.25s ease-out;
z-index: 2;
}
.network-selector-close {
flex-shrink: 0;
padding: 0 $network-selector-horizontal-padding;
margin: 0 0 8px;
svg {
cursor: pointer;
display: block;
margin-left: auto;
}
path {
fill: $network-selector-close-color;
}
}
.network-selector-text-container {
flex-shrink: 0;
margin: 0 0 15px;
padding: 0 $network-selector-horizontal-padding;
}
.network-selector-title {
color: #333;
font-size: 18px;
font-weight: normal;
line-height: 1.2;
margin: 0 0 10px;
padding: 0;
}
.network-selector-text {
color: #a3a9b5;
font-size: 12px;
font-weight: normal;
line-height: 1.67;
margin: 0;
padding: 0;
}
.network-selector-search-container {
align-items: center;
background-color: #f5f6fa;
display: flex;
flex-shrink: 0;
height: 62px;
margin: 0;
padding: 0 $network-selector-horizontal-padding;
path {
flex-grow: 0;
flex-shrink: 0;
fill: $network-selector-search-input-color;
}
}
.network-selector-search-input {
background-color: transparent;
border-color: transparent;
color: #333;
flex-grow: 1;
font-size: 14px;
font-weight: 600;
height: 100%;
outline: none;
padding: 0 20px 0 10px;
&[placeholder]{
color: $network-selector-search-input-color !important;
}
&::-webkit-input-placeholder { /* Chrome/Opera/Safari */
color: $network-selector-search-input-color !important;
}
&::-moz-placeholder { /* Firefox 19+ */
color: $network-selector-search-input-color !important;
}
&:-ms-input-placeholder { /* IE 10+ */
color: $network-selector-search-input-color !important;
}
&:-moz-placeholder { /* Firefox 18- */
color: $network-selector-search-input-color !important;
}
}
.network-selector-tabs-container {
border-bottom: 1px solid $base-border-color;
display: flex;
flex-shrink: 0;
margin: 0 $network-selector-horizontal-padding;
}
.network-selector-tab {
color: #a3a9b5;
cursor: pointer;
flex-shrink: 1;
font-size: 14px;
font-weight: 600;
line-height: 1.2;
min-width: 0;
padding: 20px 18px 15px;
position: relative;
text-align: center;
user-select: none;
white-space: nowrap;
&:hover {
color: #333;
}
&.active {
color: #333;
cursor: default;
&::after {
background-color: $network-selector-tab-active-border-color;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
bottom: 0;
content: "";
height: 4px;
left: 0;
position: absolute;
right: 0;
}
}
}
.network-selector-tab-content {
display: none;
&.active {
display: block;
}
}
.network-selector-item {
border-bottom: 1px solid $base-border-color;
display: flex;
position: relative;
.radio {
cursor: pointer;
margin: 0 15px 0 0;
input[type="radio"] {
cursor: pointer;
}
}
.radio-icon {
margin: 0;
}
&:last-child {
border-bottom: none;
}
}
.network-selector-item-url {
align-items: center;
cursor: pointer;
display: flex;
flex-grow: 1;
margin: 0;
padding: 20px 0;
&:hover {
.network-selector-item-type {
color: #333;
}
}
}
.network-selector-item-icon {
background-color: #dfdfdf;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: contain;
border-radius: 50%;
flex-grow: 0;
flex-shrink: 0;
height: $network-selector-item-icon-dimensions;
margin: 0 15px 0 0;
width: $network-selector-item-icon-dimensions;
}
.network-selector-item-title {
color: #333;
flex-grow: 1;
font-size: 14px;
font-weight: normal;
line-height: 1.2;
overflow: hidden;
text-align: left;
text-overflow: ellipsis;
user-select: none;
white-space: nowrap;
}
.network-selector-item-type {
color: #a3a9b5;
flex-shrink: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.2;
padding-left: 10px;
text-align: right;
user-select: none;
white-space: nowrap;
}
.network-selector-item-content {
align-items: center;
display: flex;
flex-grow: 1;
}
.network-selector-networks-container {
flex-grow: 1;
flex-shrink: 1;
min-height: 100px;
overflow: auto;
padding: 0 $network-selector-horizontal-padding;
}
.network-selector-load-more-container {
flex-shrink: 1;
padding: 0 $network-selector-horizontal-padding;
.btn-network-selector-load-more {
@include btn-line($btn-network-selector-load-more-background, $btn-network-selector-load-more-color);
width: 100%;
}
}
.network-selector-item-favorite {
align-items: center;
cursor: pointer;
display: flex;
flex-grow: 1;
flex-shrink: 0;
margin: 0;
max-width: 36px;
padding-left: 20px;
position: relative;
input[type="checkbox"] {
cursor: pointer;
height: 100%;
opacity: 0;
position: absolute;
width: 100%;
z-index: 5;
&:checked + svg {
position: relative;
z-index: 1;
path {
fill: #ffb20d;
}
}
}
&:hover {
path {
fill: rgba(#ffb20d, 0.4);
}
}
}
.network-selector-tab-content-empty {
font-size: 16px;
font-weight: 600;
padding: 40px;
text-align: center;
}

@ -0,0 +1,49 @@
$radio-color: $primary !default;
$radio-dimensions: 20px !default;
.radio {
align-items: center;
display: flex;
position: relative;
input[type="radio"] {
height: 100%;
opacity: 0;
position: absolute;
width: 100%;
z-index: 5;
&:checked + .radio-icon::before {
background-color: $radio-color;
border-radius: 50%;
content: "";
height: 12px;
left: 50%;
position: absolute;
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 12px;
}
}
.radio-icon {
border: 1px solid $base-border-color;
border-radius: 50%;
flex-grow: 0;
flex-shrink: 0;
height: $radio-dimensions;
margin: 0 10px 0 0;
position: relative;
width: $radio-dimensions;
z-index: 1;
}
.radio-text {
font-size: 14px;
font-weight: normal;
line-height: 1.2;
position: relative;
white-space: nowrap;
z-index: 1;
}
}

@ -1,6 +1,45 @@
.transaction-details-address {
font-size: 12px;
font-weight: bold;
line-height: 1.2;
margin: 0 0 12px;
.transaction-bottom-panel {
display: flex;
flex-direction: column;
@media (min-width: 768px) {
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
}
}
.transaction-bottom-panel {
display: flex;
flex-direction: column;
@media (min-width: 768px) {
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
}
}
.download-all-transactions {
text-align: center;
color: #a3a9b5;
font-size: 13px;
margin-top: 10px;
@media (min-width: 768px) {
margin-top: 30px;
}
.download-all-transactions-link {
text-decoration: none;
svg {
position: relative;
margin-left: 2px;
top: -3px;
path {
fill: $primary;
}
}
&:hover {
span {
text-decoration: underline;
}
}
}
}

@ -31,6 +31,8 @@ import './pages/chain'
import './pages/pending_transactions'
import './pages/transaction'
import './pages/transactions'
import './pages/favorites'
import './pages/network-search'
import './pages/layout'
import './pages/admin/tasks.js'
@ -57,3 +59,4 @@ import './lib/tooltip'
import './lib/modals'
import './lib/try_api'
import './lib/card_tabs'
import './lib/network_selector'

@ -219,6 +219,14 @@ export const elements = {
$el.hide()
}
},
'[csv-download]': {
render ($el, state) {
if (state.emptyResponse) {
return $el.hide()
}
return $el.show()
}
}
}

@ -0,0 +1,77 @@
import $ from 'jquery'
$(function () {
const mainBody = $('body')
const showNetworkSelector = $('.js-show-network-selector')
const hideNetworkSelector = $('.js-network-selector-close')
const hideNetworkSelectorOverlay = $('.js-network-selector-overlay-close')
const networkSelector = $('.js-network-selector')
const networkSelectorOverlay = $('.js-network-selector-overlay')
const networkSelectorTab = $('.js-network-selector-tab')
const networkSelectorTabContent = $('.js-network-selector-tab-content')
const networkSelectorItemURL = $('.js-network-selector-item-url')
const FADE_IN_DELAY = 250
showNetworkSelector.on('click', (e) => {
e.preventDefault()
openNetworkSelector()
})
hideNetworkSelector.on('click', (e) => {
e.preventDefault()
closeNetworkSelector()
})
hideNetworkSelectorOverlay.on('click', (e) => {
e.preventDefault()
closeNetworkSelector()
})
networkSelectorTab.on('click', function (e) {
e.preventDefault()
setNetworkTab($(this))
})
networkSelectorItemURL.on('click', function (e) {
window.location = $(this).attr('network-selector-item-url')
})
let setNetworkTab = (currentTab) => {
if (currentTab.hasClass('active')) return
networkSelectorTab.removeClass('active')
currentTab.addClass('active')
networkSelectorTabContent.removeClass('active')
$(`[network-selector-tab="${currentTab.attr('network-selector-tab-filter')}"]`).addClass('active')
}
let openNetworkSelector = () => {
mainBody.addClass('network-selector-visible')
networkSelectorOverlay.fadeIn(FADE_IN_DELAY)
setNetworkSelectorVisiblePosition()
}
let closeNetworkSelector = () => {
mainBody.removeClass('network-selector-visible')
networkSelectorOverlay.fadeOut(FADE_IN_DELAY)
setNetworkSelectorHiddenPosition()
}
let getNetworkSelectorWidth = () => {
return parseInt(networkSelector.css('width')) || parseInt(networkSelector.css('max-width'))
}
let setNetworkSelectorHiddenPosition = () => {
return networkSelector.css({ 'right': `-${getNetworkSelectorWidth()}px` })
}
let setNetworkSelectorVisiblePosition = () => {
return networkSelector.css({ 'right': '0' })
}
let init = () => {
setNetworkSelectorHiddenPosition()
}
init()
})

@ -0,0 +1,58 @@
import $ from 'jquery'
var favoritesContainer = $('.js-favorites-tab')
var favoritesNetworksUrls = []
if (localStorage.getItem('favoritesNetworksUrls') === null) {
localStorage.setItem('favoritesNetworksUrls', JSON.stringify(favoritesNetworksUrls))
} else {
favoritesNetworksUrls = JSON.parse(localStorage.getItem('favoritesNetworksUrls'))
}
$(document).on('change', ".network-selector-item-favorite input[type='checkbox']", function () {
var networkUrl = $(this).attr('data-url')
var thisStatus = $(this).is(':checked')
var workWith = $(".network-selector-item[data-url='" + networkUrl + "'")
// Add new checkbox status to same network in another tabs
$(".network-selector-item-favorite input[data-url='" + networkUrl + "']").prop('checked', thisStatus)
// Clone
var parent = $(".network-selector-item[data-url='" + networkUrl + "'").clone()
// Push or remove favorite networks to array
var found = $.inArray(networkUrl, favoritesNetworksUrls)
if (found < 0 && thisStatus === true) {
favoritesNetworksUrls.push(networkUrl)
} else {
var index = favoritesNetworksUrls.indexOf(networkUrl)
if (index !== -1) {
favoritesNetworksUrls.splice(index, 1)
}
}
// Push to localstorage
var willBePushed = JSON.stringify(favoritesNetworksUrls)
localStorage.setItem('favoritesNetworksUrls', willBePushed)
// Append or remove item from 'favorites' tab
if (thisStatus === true) {
favoritesContainer.append(parent[0])
$('.js-favorites-tab .network-selector-tab-content-empty').hide()
} else {
var willRemoved = favoritesContainer.find(workWith)
willRemoved.remove()
if (favoritesNetworksUrls.length === 0) {
$('.js-favorites-tab .network-selector-tab-content-empty').show()
}
}
})
if (favoritesNetworksUrls.length > 0) {
$('.js-favorites-tab .network-selector-tab-content-empty').hide()
for (var i = 0; i < favoritesNetworksUrls.length + 1; i++) {
$(".network-selector-item[data-url='" + favoritesNetworksUrls[i] + "'").find('input[data-url]').prop('checked', true)
var parent = $(".network-selector-item[data-url='" + favoritesNetworksUrls[i] + "'").clone()
favoritesContainer.append(parent[0])
}
}

@ -0,0 +1,21 @@
import $ from 'jquery'
var networkSearchInput = $('.network-selector-search-input')
var networkSearchInputVal = ''
$(networkSearchInput).on('input', function () {
networkSearchInputVal = $(this).val()
$.expr[':'].Contains = $.expr.createPseudo(function (arg) {
return function (elem) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0
}
})
if (networkSearchInputVal === '') {
$('.network-selector-item').show()
} else {
$('.network-selector-item').hide()
$(".network-selector-item:Contains('" + networkSearchInputVal + "')").show()
}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 60 60">
<g>
<path d="M.87,4h0V26.18a1.35,1.35,0,0,0,1.35,1.37l9.91,0a1.37,1.37,0,0,0,1.16-2L12,23.19h0a2,2,0,0,0-2.75-.75h0l-.14.08h0a2,2,0,0,1-2.72-.74,2.06,2.06,0,0,1-.16-1.65h0l2.06-6.28h0a2,2,0,0,1,2.31-1.36h0L17,13.8h0a2,2,0,0,1,1.33,1,2,2,0,0,1-.73,2.77h0l-.14.08h0a2.07,2.07,0,0,0-.74,2.8h0L18,22.65a1.34,1.34,0,0,0,2.32,0l5-8.66a1.37,1.37,0,0,0-.49-1.86L5.9,1.06h0A3.36,3.36,0,0,0,.87,4Z"/>
<path d="M50.9,26.32h0L30.58,14.37a1.34,1.34,0,0,0-1.85.5L23.4,24.36a1.47,1.47,0,0,0,1.25,2.19h3.48a1.45,1.45,0,0,0,1.44-1.47V24A1.34,1.34,0,0,1,30.9,22.6h.92a1.33,1.33,0,0,1,1,.46l4.84,5.56a1.38,1.38,0,0,1,0,1.81L32.83,36a1.33,1.33,0,0,1-1,.46H30.9a1.34,1.34,0,0,1-1.33-1.35V34a1.45,1.45,0,0,0-1.44-1.47H24.7a1.47,1.47,0,0,0-1.25,2.19l5.29,9.43a1.33,1.33,0,0,0,1.83.49L50.9,32.67h0A3.7,3.7,0,0,0,50.9,26.32Z"/>
<path d="M5.9,58.94h0L24.76,47.87a1.39,1.39,0,0,0,.5-1.88l-5-8.71a1.34,1.34,0,0,0-2.32,0l-1.62,2.86a1.38,1.38,0,0,0,.5,1.87l1.27.75a1.38,1.38,0,0,1,.5,1.86l-.48.84a1.34,1.34,0,0,1-.89.65L10,47.61a1.34,1.34,0,0,1-1.54-.91L6.08,39.56a1.39,1.39,0,0,1,.11-1.12l.47-.83a1.34,1.34,0,0,1,1.84-.49l1.27.75a1.33,1.33,0,0,0,1.83-.49l1.61-2.83a1.37,1.37,0,0,0-1.16-2l-9.84,0A1.35,1.35,0,0,0,.87,33.82V56h0A3.36,3.36,0,0,0,5.9,58.94Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
<path fill="#5C34A2" fill-rule="evenodd" d="M15 0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-8.284 0-15-6.716-15-15C0 6.716 6.716 0 15 0z"/>
<path fill="#FFF" fill-rule="evenodd" d="M8.438 16.812h-.313v.875h-.007c.001.007.007.01.007.016 0 .164-.14.297-.313.297h-2.5A.305.305 0 0 1 5 17.703c0-.006.006-.009.007-.016H5v-5.374h.007c-.001-.007-.007-.01-.007-.016 0-.164.14-.297.312-.297h3.126c1.38 0 2.5 1.077 2.5 2.406 0 1.329-1.12 2.406-2.5 2.406zM14.688 12c1.725 0 3.125 1.343 3.125 3s-1.4 3-3.125 3c-1.726 0-3.126-1.343-3.126-3s1.4-3 3.126-3zM25 17.81a.19.19 0 0 1-.193.185h-7.108c-.004.001-.007.005-.011.005a.188.188 0 0 1-.188-.188c0-.039.021-.07.042-.101l-.007-.012 3.52-5.549h.016c.02-.082.086-.148.177-.148.092 0 .158.066.178.148h.016L25 17.736l-.02.027c.005.017.02.029.02.047z"/>
</svg>

After

Width:  |  Height:  |  Size: 868 B

@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="25" viewBox="0 0 43.5 43.5">
<defs>
<style>
.a {
fill: #fff;
filter: url(#b);
}
.b {
fill: url(#a);
}
</style>
<linearGradient id="a" x1="21" y1="12.89" x2="21" y2="28.58" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fec54c"/>
<stop offset="1" stop-color="#fe9314"/>
</linearGradient>
<filter filterUnits="userSpaceOnUse" height="49" id="b" width="43" x="0" y="0">
<feOffset dy="3" in="SourceAlpha"></feOffset>
<feGaussianBlur result="blurOut" stdDeviation="2.236"></feGaussianBlur>
<feFlood flood-color="#ABBAC7" result="floodOut"></feFlood>
<feComposite in="floodOut" in2="blurOut" operator="atop"></feComposite>
<feComponentTransfer>
<feFuncA slope=".2" type="linear"></feFuncA>
</feComponentTransfer>
<feMerge>
<feMergeNode></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<path class="a" d="M17.2,38.8,6,32.1a4.34,4.34,0,0,1-2-3.4V12.9A4.11,4.11,0,0,1,6,9.5L17.2,2.8C21,.5,21,.5,24.9,2.8L36,9.4a4.22,4.22,0,0,1,2,3.4V28.6A4.22,4.22,0,0,1,36,32L24.9,38.7C21,41.1,21,41.1,17.2,38.8Z"/>
<polygon class="b" points="30.03 12.89 24.97 12.89 21.03 17.64 17.03 12.89 11.97 12.89 18.53 20.82 11.97 28.7 17.03 28.7 20.97 23.95 24.97 28.7 30.03 28.7 23.47 20.76 30.03 12.89"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
<path fill="#38A9F5" fill-rule="evenodd" d="M15 0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-8.284 0-15-6.716-15-15C0 6.716 6.716 0 15 0z"/>
<path fill="#FFF" fill-rule="evenodd" d="M24.22 20h-6.449c-.089 0-.178-.034-.266-.06l.013.06h-2.781l-.836-3.687H5.437v-.078c-.245-.038-.437-.277-.437-.579v-4.469h.003c.007-.65.448-1.173.997-1.183V10h15.95c.558 0 1.133.535 1.282 1.194l1.729 7.612c.149.659-.182 1.194-.741 1.194zM9.054 11.84H6.776l.61 2.638h2.279l-.611-2.638zm3.78 0h-2.279l.611 2.638h2.278l-.61-2.638zm6.226 6.841h1.05l-.282-1.308h-1.05l.282 1.308zm2.761-6.841h-4.375l1.175 5.001h4.376l-1.176-5.001zm1.343 5.533h-1.05l.282 1.308h1.05l-.282-1.308zm-17.727.002H11.664v-.003h1.452L13.668 20H6.125v-.026c-.038.005-.071.026-.109.026-.51 0-.914-.452-.987-1.031H5v-.813h.082c-.038-.077-.082-.153-.082-.25 0-.293.196-.531.437-.531z"/>
</svg>

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30">
<path fill="#6EC9B9" fill-rule="evenodd" d="M15 0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-8.284 0-15-6.716-15-15C0 6.716 6.716 0 15 0z"/>
<path fill="#FFF" fill-rule="evenodd" d="M24.22 20h-6.449c-.089 0-.178-.034-.266-.06l.013.06h-2.781l-.836-3.687H5.437v-.078c-.245-.038-.437-.277-.437-.579v-4.469h.003c.007-.65.448-1.173.997-1.183V10h15.95c.558 0 1.133.535 1.282 1.194l1.729 7.612c.149.659-.182 1.194-.741 1.194zM9.054 11.84H6.776l.61 2.637h2.279l-.611-2.637zm3.78 0h-2.279l.611 2.637h2.278l-.61-2.637zm6.226 6.841h1.05l-.282-1.308h-1.05l.282 1.308zm2.761-6.841h-4.375l1.175 5.001h4.376l-1.176-5.001zm1.343 5.533h-1.05l.282 1.308h1.05l-.282-1.308zm-17.727.002H11.664v-.003h1.452L13.668 20H6.125v-.026c-.038.005-.071.026-.109.026-.51 0-.914-.452-.987-1.031H5v-.813h.082c-.038-.077-.082-.153-.082-.25 0-.293.196-.531.437-.531z"/>
</svg>

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

@ -41,7 +41,7 @@ config :block_scout_web, BlockScoutWeb.Endpoint,
]
],
url: [
host: "localhost",
host: System.get_env("BLOCKSCOUT_HOST") || "localhost",
path: System.get_env("NETWORK_PATH") || "/"
],
render_errors: [view: BlockScoutWeb.ErrorView, accepts: ~w(html json)],

@ -10,6 +10,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
alias BlockScoutWeb.TransactionView
alias Explorer.{Chain, Market}
alias Explorer.Chain.{AddressTokenTransferCsvExporter, AddressTransactionCsvExporter}
alias Explorer.ExchangeRates.Token
alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View
@ -106,4 +107,44 @@ defmodule BlockScoutWeb.AddressTransactionController do
not_found(conn)
end
end
def token_transfers_csv(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
address
|> AddressTokenTransferCsvExporter.export()
|> Enum.into(
conn
|> put_resp_content_type("application/csv")
|> put_resp_header("content-disposition", "attachment; filename=token_transfers.csv")
|> send_chunked(200)
)
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
def transactions_csv(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
address
|> AddressTransactionCsvExporter.export()
|> Enum.into(
conn
|> put_resp_content_type("application/csv")
|> put_resp_header("content-disposition", "attachment; filename=transactions.csv")
|> send_chunked(200)
)
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
end

@ -242,8 +242,12 @@ defmodule BlockScoutWeb.Router do
get("/search_logs", AddressLogsController, :search_logs)
get("/transactions_csv", AddressTransactionController, :transactions_csv)
get("/token_autocomplete", ChainController, :token_autocomplete)
get("/token_transfers_csv", AddressTransactionController, :token_transfers_csv)
get("/chain_blocks", ChainController, :chain_blocks, as: :chain_blocks)
get("/api_docs", APIDocsController, :index)

@ -5,8 +5,8 @@
<%= if assigns[:truncate] do %>
<%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %>
<% else %>
<span class="d-none d-md-none d-lg-inline"><%= @address %></span>
<span class="d-md-inline-block d-lg-none"><%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %></span>
<span class="d-none d-md-none d-xl-inline"><%= @address %></span>
<span class="d-md-inline-block d-xl-none"><%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %></span>
<% end %>
<% end %>
</span>

@ -67,8 +67,17 @@
</div>
<div data-items></div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<!--<div class="transaction-bottom-panel">
<div class="download-all-transactions">
Download <a class="download-all-transactions-link" href=<%= address_transaction_path(@conn, :token_transfers_csv, %{"address_id" => to_string(@address.hash)}) %>><%= gettext("CSV") %></span>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16">
<path fill="#333333" fill-rule="evenodd" d="M13 16H1c-.999 0-1-1-1-1V1s-.004-1 1-1h6l7 7v8s-.032 1-1 1zm-1-8c0-.99-1-1-1-1H8s-1 .001-1-1V3c0-.999-1-1-1-1H2v12h10V8z"/>
</svg>
</a>
</div>-->
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<!--</div>-->
</div>
</div>

@ -21,7 +21,17 @@
<div data-items></div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<div class="transaction-bottom-panel">
<div csv-download class="download-all-transactions">
Download <a class="download-all-transactions-link" href=<%= address_transaction_path(@conn, :token_transfers_csv, %{"address_id" => to_string(@address.hash)}) %>><%= gettext("CSV") %></span>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16">
<path fill="#333333" fill-rule="evenodd" d="M13 16H1c-.999 0-1-1-1-1V1s-.004-1 1-1h6l7 7v8s-.032 1-1 1zm-1-8c0-.99-1-1-1-1H8s-1 .001-1-1V3c0-.999-1-1-1-1H2v12h10V8z"/>
</svg>
</a>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
</div>
</div>
</div>
</section>

@ -51,6 +51,8 @@
</div>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "top", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<button data-error-message class="alert alert-danger col-12 text-left" style="display: none;">
@ -64,8 +66,17 @@
</div>
<div data-items></div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<div class="transaction-bottom-panel">
<div class="download-all-transactions">
Download <a class="download-all-transactions-link" href=<%= address_transaction_path(@conn, :token_transfers_csv, %{"address_id" => to_string(@address.hash)}) %>><%= gettext("CSV") %></span>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16">
<path fill="#333333" fill-rule="evenodd" d="M13 16H1c-.999 0-1-1-1-1V1s-.004-1 1-1h6l7 7v8s-.032 1-1 1zm-1-8c0-.99-1-1-1-1H8s-1 .001-1-1V3c0-.999-1-1-1-1H2v12h10V8z"/>
</svg>
</a>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
</div>
</div>
</div>

@ -2,9 +2,9 @@
<div class="card">
<div class="card-body">
<h1 class="card-title margin-bottom-sm"><%= gettext("ETH RPC API Documentation") %></h2>
<p class="api-text-monospace" data-endpoint-url="<%= BlockScoutWeb.Endpoint.url() %>/api/eth_rpc">[ <%= gettext "Base URL:" %> <%= @conn.host %>/api/eth_rpc ]</p>
<p class="api-text-monospace" data-endpoint-url="<%= BlockScoutWeb.Endpoint.url() %>/api/eth_rpc">[ <%= gettext "Base URL:" %> <%= url() %>/api/eth_rpc ]</p>
<p class="card-subtitle margin-bottom-0">
<%= gettext "This API is provided to support some rpc methods in the exact format specified for ethereum nodes, which can be found " %>
<%= gettext "This API is provided to support some rpc methods in the exact format specified for ethereum nodes, which can be found " %>
<a href="https://github.com/ethereum/wiki/wiki/JSON-RPC"><%= gettext "here." %></a>
<%= gettext "This is useful to allow sending requests to blockscout without having to change anything about the request." %>

@ -2,7 +2,7 @@
<div class="card">
<div class="card-body">
<h1 class="card-title margin-bottom-sm"><%= gettext("API Documentation") %></h2>
<p class="api-text-monospace" data-endpoint-url="<%= BlockScoutWeb.Endpoint.url() %>/api">[ <%= gettext "Base URL:" %> <%= @conn.host %>/api ]</p>
<p class="api-text-monospace" data-endpoint-url="<%= BlockScoutWeb.Endpoint.url() %>/api">[ <%= gettext "Base URL:" %> <%= url() %>/api ]</p>
<p class="card-subtitle margin-bottom-0"><%= gettext "This API is provided for developers transitioning their applications from Etherscan to BlockScout. It supports GET and POST requests." %></p>
</div>
<div class="api-anchors-list">

@ -0,0 +1,53 @@
<div class="network-selector-overlay js-network-selector-overlay">
<div class="network-selector-overlay-close js-network-selector-overlay-close"></div>
<div class="network-selector-wrapper">
<div class="network-selector js-network-selector">
<div class="network-selector-close js-network-selector-close">
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13">
<path fill-rule="evenodd" d="M7.881 6.5l4.834 4.834a.977.977 0 0 1-1.381 1.381L6.5 7.881l-4.834 4.834a.977.977 0 0 1-1.381-1.381L5.119 6.5.285 1.666A.977.977 0 0 1 1.666.285L6.5 5.119 11.334.285a.977.977 0 0 1 1.381 1.381L7.881 6.5z"/>
</svg>
</div>
<div class="network-selector-text-container">
<h1 class="network-selector-title"><%= gettext("Change Network") %></h1>
<p class="network-selector-text"><%= gettext("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore.") %></p>
</div>
<form class="network-selector-search-container">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17">
<path fill-rule="evenodd" d="M15.713 15.727a.982.982 0 0 1-1.388 0l-2.289-2.29C10.773 14.403 9.213 15 7.5 15A7.5 7.5 0 1 1 15 7.5c0 1.719-.602 3.285-1.575 4.55l2.288 2.288a.983.983 0 0 1 0 1.389zM7.5 2a5.5 5.5 0 1 0 0 11 5.5 5.5 0 1 0 0-11z"/>
</svg>
<input class="network-selector-search-input" type="text" placeholder='<%= gettext("Search network") %>' />
</form>
<div class="network-selector-tabs-container">
<div class="network-selector-tab js-network-selector-tab active" network-selector-tab-filter="all"><%= gettext("All") %></div>
<div class="network-selector-tab js-network-selector-tab" network-selector-tab-filter="mainnet"><%= gettext("Mainnet") %></div>
<div class="network-selector-tab js-network-selector-tab" network-selector-tab-filter="testnet"><%= gettext("Testnet") %></div>
<div class="network-selector-tab js-network-selector-tab" network-selector-tab-filter="favorites"><%= gettext("Favorites") %></div>
</div>
<div class="network-selector-networks-container">
<% main_nets = dropdown_main_nets() %>
<% test_nets = dropdown_test_nets() %>
<div class="network-selector-tab-content js-network-selector-tab-content active" network-selector-tab="all">
<%= for %{url: url, title: title} <- main_nets do %>
<%= render BlockScoutWeb.LayoutView, "_network_selector_item.html", title: title, url: url, tab_type: "Mainnet" %>
<% end %>
<%= for %{url: url, title: title} <- test_nets do %>
<%= render BlockScoutWeb.LayoutView, "_network_selector_item.html", title: title, url: url, tab_type: "Testnet" %>
<% end %>
</div>
<div class="network-selector-tab-content js-network-selector-tab-content" network-selector-tab="mainnet">
<%= for %{url: url, title: title} <- main_nets do %>
<%= render BlockScoutWeb.LayoutView, "_network_selector_item.html", title: title, url: url, tab_type: "Mainnet" %>
<% end %>
</div>
<div class="network-selector-tab-content js-network-selector-tab-content" network-selector-tab="testnet">
<%= for %{url: url, title: title} <- test_nets do %>
<%= render BlockScoutWeb.LayoutView, "_network_selector_item.html", title: title, url: url, tab_type: "Testnet" %>
<% end %>
</div>
<div class="network-selector-tab-content js-network-selector-tab-content js-favorites-tab" network-selector-tab="favorites">
<div class="network-selector-tab-content-empty">No content.</div>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,25 @@
<div class="network-selector-item" data-url="<%= @url %>" data-name="<%= @title %>">
<label class="network-selector-item-url js-network-selector-item-url" network-selector-item-url="<%= @url %>">
<span class="radio">
<input type="radio" name="networkSelectorItem" <%= if @title == subnetwork_title() do %> checked="true" <% end %> />
<span class="radio-icon"></span>
</span>
<span class="network-selector-item-content">
<span class='network-selector-item-icon network-selector-item-icon-<%= String.downcase(String.replace(@title, " ", "-")) %>' style="background-image: url('/images/network-selector-icons/<%= String.downcase(String.replace(@title, " ", "-")) %>.png');"></span>
<span class="network-selector-item-title">
<%= @title %>
</span>
<%= if @tab_type do %>
<span class="network-selector-item-type">
<%= @tab_type %>
</span>
<% end %>
</span>
</label>
<label class="network-selector-item-favorite">
<input type="checkbox" data-url="<%= @url %>" />
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="15">
<path fill="#E2E5EC" fill-rule="evenodd" d="M15.647 6.795c.315-.3.426-.741.29-1.151a1.135 1.135 0 0 0-.926-.764l-3.871-.551a.501.501 0 0 1-.381-.271L9.028.624A1.143 1.143 0 0 0 8-.001c-.44 0-.834.24-1.028.625L5.24 4.059a.506.506 0 0 1-.381.271l-3.871.55c-.435.062-.79.355-.926.765-.136.409-.025.85.29 1.15l2.801 2.673a.492.492 0 0 1 .146.439l-.661 3.774c-.058.333.031.656.25.911.342.397.937.518 1.414.272l3.462-1.782a.53.53 0 0 1 .471 0l3.463 1.782a1.16 1.16 0 0 0 1.413-.272c.22-.255.309-.579.25-.911L12.7 9.907a.489.489 0 0 1 .146-.439l2.801-2.673z"/>
</svg>
</label>
</div>

@ -82,26 +82,12 @@
</div>
</li>
<li class="nav-item dropdown nav-item-networks">
<a class="nav-link topnav-nav-link <%= if dropdown_nets() == [], do: "disabled", else: "dropdown-toggle" %>" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<a class="nav-link topnav-nav-link dropdown-toggle active-icon js-show-network-selector <%= if dropdown_nets() == [], do: "disabled" %>" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="nav-link-icon">
<%= render BlockScoutWeb.IconsView, "_active_icon.html" %>
</span>
<%= subnetwork_title() %>
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item header division">Mainnets</a>
<%= for %{url: url, title: title} <- dropdown_head_main_nets() do %>
<a class="dropdown-item" href="<%= url%>"><%= title %></a>
<% end %>
<a class="dropdown-item header division">Testnets</a>
<%= for %{url: url, title: title} <- test_nets(dropdown_nets()) do %>
<a class="dropdown-item" href="<%= url%>"><%= title %></a>
<% end %>
<a class="dropdown-item header division">Other Networks</a>
<%= for %{url: url, title: title} <- dropdown_other_nets() do %>
<a class="dropdown-item" href="<%= url%>"><%= title %></a>
<% end %>
</div>
</li>
</ul>
<!-- Search navbar -->
@ -136,3 +122,4 @@
</div>
</div>
</nav>
<%= render BlockScoutWeb.LayoutView, "_network_selector.html" %>

@ -27,8 +27,17 @@
</div>
<div data-items></div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<!--<div class="transaction-bottom-panel">
<div class="download-all-transactions">
Download <a class="download-all-transactions-link" href=<%= address_transaction_path(@conn, :token_transfers_csv, %{"address_id" => to_string(@address.hash)}) %>><%= gettext("CSV") %></span>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="16">
<path fill="#333333" fill-rule="evenodd" d="M13 16H1c-.999 0-1-1-1-1V1s-.004-1 1-1h6l7 7v8s-.032 1-1 1zm-1-8c0-.99-1-1-1-1H8s-1 .001-1-1V3c0-.999-1-1-1-1H2v12h10V8z"/>
</svg>
</a>
</div>-->
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<!--</div>-->
</div>
</div>

@ -170,17 +170,21 @@
</div>
<%= case token_transfer_type(@transaction) do %>
<% {type, token_transfer} -> %>
<% {type, transaction_with_transfers} when is_atom(type) -> %>
<div class="col-md-12 col-lg-4 d-flex flex-column flex-md-row flex-lg-column pl-0">
<!-- Value -->
<div class="card card-background-1 flex-grow-1">
<div class="card-body card-body-flex-column-space-between">
<h2 class="card-title balance-card-title"><%= if type == :erc20, do: gettext("ERC-20"), else: gettext("ERC-721")%><%= gettext " Token Transfer" %></h2>
<h2 class="card-title balance-card-title"><%= token_type_name(type)%><%= gettext " Token Transfer" %></h2>
<div class="text-right">
<%= for transfer <- transaction_with_transfers.token_transfers do %>
<h3 class="address-balance-text">
<%= token_transfer_amount(token_transfer) %>
<%= link(token_symbol(token_transfer.token), to: token_path(BlockScoutWeb.Endpoint, :show, token_transfer.token.contract_address_hash)) %>
<%= token_transfer_amount(transfer) %>
<%= link(token_symbol(transfer.token), to: token_path(BlockScoutWeb.Endpoint, :show, transfer.token.contract_address_hash)) %>
</h3>
<% end %>
</div>
</div>
</div>

@ -1,7 +1,7 @@
defmodule BlockScoutWeb.APIDocsView do
use BlockScoutWeb, :view
alias BlockScoutWeb.LayoutView
alias BlockScoutWeb.{Endpoint, LayoutView}
def action_tile_id(module, action) do
"#{module}-#{action}"
@ -33,4 +33,12 @@ defmodule BlockScoutWeb.APIDocsView do
"&#{param.key}=" <> "{<strong>#{param.placeholder}</strong>}"
end)
end
defp url do
if System.get_env("BLOCKSCOUT_HOST") do
"http://" <> System.get_env("BLOCKSCOUT_HOST")
else
Endpoint.url()
end
end
end

@ -198,6 +198,16 @@ defmodule BlockScoutWeb.LayoutView do
|> Enum.reject(&Map.get(&1, :hide_in_dropdown?))
end
def dropdown_main_nets do
dropdown_nets()
|> main_nets()
end
def dropdown_test_nets do
dropdown_nets()
|> test_nets()
end
def dropdown_head_main_nets do
dropdown_nets()
|> main_nets()

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.TransactionView do
alias BlockScoutWeb.{AddressView, BlockView, TabHelpers}
alias Cldr.Number
alias Explorer.Chain
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block.Reward
alias Explorer.Chain.{Address, Block, InternalTransaction, Transaction, Wei}
alias Explorer.ExchangeRates.Token
@ -33,7 +33,18 @@ defmodule BlockScoutWeb.TransactionView do
def value_transfer?(_), do: false
def token_transfer_type(transaction) do
Chain.transaction_token_transfer_type(transaction)
transaction_with_transfers = Repo.preload(transaction, token_transfers: :token)
type = Chain.transaction_token_transfer_type(transaction)
if type, do: {type, transaction_with_transfers}
end
def token_type_name(type) do
case type do
:erc20 -> gettext("ERC-20 ")
:erc721 -> gettext("ERC-721 ")
:token_transfer -> ""
end
end
def processing_time_duration(%Transaction{block: nil}) do

@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:133
#: lib/block_scout_web/views/transaction_view.ex:144
msgid "(Awaiting internal transactions for status)"
msgstr ""
@ -112,6 +112,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:27
#: lib/block_scout_web/templates/address_transaction/index.html.eex:23
#: lib/block_scout_web/templates/layout/_network_selector.html.eex:21
#: lib/block_scout_web/views/address_internal_transaction_view.ex:8
#: lib/block_scout_web/views/address_transaction_view.ex:8
msgid "All"
@ -275,12 +276,12 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:210
#: lib/block_scout_web/views/transaction_view.ex:221
msgid "Contract Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:209
#: lib/block_scout_web/views/transaction_view.ex:220
msgid "Contract Creation"
msgstr ""
@ -363,12 +364,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:137
#: lib/block_scout_web/views/transaction_view.ex:148
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:135
#: lib/block_scout_web/views/transaction_view.ex:146
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@ -378,7 +379,7 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:55
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:30
#: lib/block_scout_web/templates/transaction/overview.html.eex:192
#: lib/block_scout_web/templates/transaction/overview.html.eex:196
#: lib/block_scout_web/views/wei_helpers.ex:78
msgid "Ether"
msgstr ""
@ -473,7 +474,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
#: lib/block_scout_web/views/address_view.ex:306
#: lib/block_scout_web/views/transaction_view.ex:263
#: lib/block_scout_web/views/transaction_view.ex:274
msgid "Internal Transactions"
msgstr ""
@ -490,7 +491,7 @@ msgid "Less than"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:220
#: lib/block_scout_web/templates/transaction/overview.html.eex:224
msgid "Limit"
msgstr ""
@ -500,7 +501,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
#: lib/block_scout_web/views/address_view.ex:312
#: lib/block_scout_web/views/transaction_view.ex:264
#: lib/block_scout_web/views/transaction_view.ex:275
msgid "Logs"
msgstr ""
@ -512,7 +513,7 @@ msgid "Market Cap"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:118
#: lib/block_scout_web/views/transaction_view.ex:129
msgid "Max of"
msgstr ""
@ -602,8 +603,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
#: lib/block_scout_web/views/transaction_view.ex:132
#: lib/block_scout_web/views/transaction_view.ex:166
#: lib/block_scout_web/views/transaction_view.ex:143
#: lib/block_scout_web/views/transaction_view.ex:177
msgid "Pending"
msgstr ""
@ -666,8 +667,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:116
#: lib/block_scout_web/templates/layout/_topnav.html.eex:133
#: lib/block_scout_web/templates/layout/_topnav.html.eex:102
#: lib/block_scout_web/templates/layout/_topnav.html.eex:119
msgid "Search"
msgstr ""
@ -690,7 +691,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
#: lib/block_scout_web/views/transaction_view.ex:134
#: lib/block_scout_web/views/transaction_view.ex:145
msgid "Success"
msgstr ""
@ -743,7 +744,7 @@ msgid "There are no tokens."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:62
#: lib/block_scout_web/templates/address_transaction/index.html.eex:64
msgid "There are no transactions for this address."
msgstr ""
@ -795,7 +796,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:5
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/views/transaction_view.ex:208
#: lib/block_scout_web/views/transaction_view.ex:219
msgid "Token Transfer"
msgstr ""
@ -805,7 +806,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
#: lib/block_scout_web/views/tokens/overview_view.ex:35
#: lib/block_scout_web/views/transaction_view.ex:262
#: lib/block_scout_web/views/transaction_view.ex:273
msgid "Token Transfers"
msgstr ""
@ -845,7 +846,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:3
#: lib/block_scout_web/views/transaction_view.ex:211
#: lib/block_scout_web/views/transaction_view.ex:222
msgid "Transaction"
msgstr ""
@ -907,7 +908,7 @@ msgid "Unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
#: lib/block_scout_web/templates/transaction/overview.html.eex:218
msgid "Used"
msgstr ""
@ -927,7 +928,7 @@ msgid "Validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:192
#: lib/block_scout_web/templates/transaction/overview.html.eex:196
msgid "Value"
msgstr ""
@ -1210,7 +1211,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:21
#: lib/block_scout_web/templates/address_token/index.html.eex:13
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:20
#: lib/block_scout_web/templates/address_transaction/index.html.eex:57
#: lib/block_scout_web/templates/address_transaction/index.html.eex:59
#: lib/block_scout_web/templates/address_validation/index.html.eex:22
#: lib/block_scout_web/templates/block_transaction/index.html.eex:23
#: lib/block_scout_web/templates/chain/show.html.eex:91
@ -1480,8 +1481,8 @@ msgid "Error: Could not determine contract creator."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:110
#: lib/block_scout_web/templates/layout/_topnav.html.eex:114
#: lib/block_scout_web/templates/layout/_topnav.html.eex:96
#: lib/block_scout_web/templates/layout/_topnav.html.eex:100
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@ -1522,16 +1523,6 @@ msgstr ""
msgid "Optimization runs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:178
msgid "ERC-20"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:178
msgid "ERC-721"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/index.html.eex:4
msgid "API Documentation"
@ -1548,14 +1539,14 @@ msgid "View All Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:210
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
msgid "Gas"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:24
#: lib/block_scout_web/templates/transaction_raw_trace/index.html.eex:7
#: lib/block_scout_web/views/transaction_view.ex:265
#: lib/block_scout_web/views/transaction_view.ex:276
msgid "Raw Trace"
msgstr ""
@ -1701,11 +1692,6 @@ msgstr ""
msgid " Token Transfer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:27
msgid "There is no decompilded contracts for this address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:14
msgid " is recommended."
@ -1731,6 +1717,11 @@ msgstr ""
msgid "However, in general, the"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:27
msgid "There is no decompilded contracts for this address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:7
msgid "This API is provided to support some rpc methods in the exact format specified for ethereum nodes, which can be found "
@ -1749,14 +1740,4 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:9
msgid "here."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:51
msgid "Constructor arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:58
msgid "External libraries"
msgstr ""
msgstr ""

@ -49,7 +49,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:133
#: lib/block_scout_web/views/transaction_view.ex:144
msgid "(Awaiting internal transactions for status)"
msgstr ""
@ -112,6 +112,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:27
#: lib/block_scout_web/templates/address_transaction/index.html.eex:23
#: lib/block_scout_web/templates/layout/_network_selector.html.eex:20
#: lib/block_scout_web/views/address_internal_transaction_view.ex:8
#: lib/block_scout_web/views/address_transaction_view.ex:8
msgid "All"
@ -275,12 +276,12 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:210
#: lib/block_scout_web/views/transaction_view.ex:221
msgid "Contract Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:209
#: lib/block_scout_web/views/transaction_view.ex:220
msgid "Contract Creation"
msgstr ""
@ -363,12 +364,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:137
#: lib/block_scout_web/views/transaction_view.ex:148
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:135
#: lib/block_scout_web/views/transaction_view.ex:146
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@ -378,7 +379,7 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:55
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:30
#: lib/block_scout_web/templates/transaction/overview.html.eex:192
#: lib/block_scout_web/templates/transaction/overview.html.eex:196
#: lib/block_scout_web/views/wei_helpers.ex:78
msgid "Ether"
msgstr "POA"
@ -473,7 +474,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
#: lib/block_scout_web/views/address_view.ex:306
#: lib/block_scout_web/views/transaction_view.ex:263
#: lib/block_scout_web/views/transaction_view.ex:274
msgid "Internal Transactions"
msgstr ""
@ -490,7 +491,7 @@ msgid "Less than"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:220
#: lib/block_scout_web/templates/transaction/overview.html.eex:224
msgid "Limit"
msgstr ""
@ -500,7 +501,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
#: lib/block_scout_web/views/address_view.ex:312
#: lib/block_scout_web/views/transaction_view.ex:264
#: lib/block_scout_web/views/transaction_view.ex:275
msgid "Logs"
msgstr ""
@ -512,7 +513,7 @@ msgid "Market Cap"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:118
#: lib/block_scout_web/views/transaction_view.ex:129
msgid "Max of"
msgstr ""
@ -602,8 +603,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
#: lib/block_scout_web/views/transaction_view.ex:132
#: lib/block_scout_web/views/transaction_view.ex:166
#: lib/block_scout_web/views/transaction_view.ex:143
#: lib/block_scout_web/views/transaction_view.ex:177
msgid "Pending"
msgstr ""
@ -666,8 +667,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:116
#: lib/block_scout_web/templates/layout/_topnav.html.eex:133
#: lib/block_scout_web/templates/layout/_topnav.html.eex:102
#: lib/block_scout_web/templates/layout/_topnav.html.eex:119
msgid "Search"
msgstr ""
@ -690,7 +691,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
#: lib/block_scout_web/views/transaction_view.ex:134
#: lib/block_scout_web/views/transaction_view.ex:145
msgid "Success"
msgstr ""
@ -733,7 +734,7 @@ msgid "There are no token transfers for this address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/index.html.eex:18
#: lib/block_scout_web/templates/address_token/index.html.eex:19
msgid "There are no tokens for this address."
msgstr ""
@ -743,7 +744,7 @@ msgid "There are no tokens."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_transaction/index.html.eex:62
#: lib/block_scout_web/templates/address_transaction/index.html.eex:64
msgid "There are no transactions for this address."
msgstr ""
@ -795,7 +796,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:5
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:4
#: lib/block_scout_web/views/transaction_view.ex:208
#: lib/block_scout_web/views/transaction_view.ex:219
msgid "Token Transfer"
msgstr ""
@ -805,13 +806,13 @@ msgstr ""
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
#: lib/block_scout_web/views/tokens/overview_view.ex:35
#: lib/block_scout_web/views/transaction_view.ex:262
#: lib/block_scout_web/views/transaction_view.ex:273
msgid "Token Transfers"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:8
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token/index.html.eex:9
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:9
#: lib/block_scout_web/views/address_view.ex:304
msgid "Tokens"
@ -845,7 +846,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:3
#: lib/block_scout_web/views/transaction_view.ex:211
#: lib/block_scout_web/views/transaction_view.ex:222
msgid "Transaction"
msgstr ""
@ -907,7 +908,7 @@ msgid "Unique Token"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
#: lib/block_scout_web/templates/transaction/overview.html.eex:218
msgid "Used"
msgstr ""
@ -927,7 +928,7 @@ msgid "Validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:192
#: lib/block_scout_web/templates/transaction/overview.html.eex:196
msgid "Value"
msgstr ""
@ -1208,9 +1209,9 @@ msgstr ""
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:61
#: lib/block_scout_web/templates/address_logs/index.html.eex:21
#: lib/block_scout_web/templates/address_token/index.html.eex:13
#: lib/block_scout_web/templates/address_token/index.html.eex:14
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:20
#: lib/block_scout_web/templates/address_transaction/index.html.eex:57
#: lib/block_scout_web/templates/address_transaction/index.html.eex:59
#: lib/block_scout_web/templates/address_validation/index.html.eex:22
#: lib/block_scout_web/templates/block_transaction/index.html.eex:23
#: lib/block_scout_web/templates/chain/show.html.eex:91
@ -1480,8 +1481,8 @@ msgid "Error: Could not determine contract creator."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:110
#: lib/block_scout_web/templates/layout/_topnav.html.eex:114
#: lib/block_scout_web/templates/layout/_topnav.html.eex:96
#: lib/block_scout_web/templates/layout/_topnav.html.eex:100
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@ -1522,16 +1523,6 @@ msgstr ""
msgid "Optimization runs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:178
msgid "ERC-20"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:178
msgid "ERC-721"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/index.html.eex:4
msgid "API Documentation"
@ -1548,14 +1539,14 @@ msgid "View All Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/overview.html.eex:210
#: lib/block_scout_web/templates/transaction/overview.html.eex:214
msgid "Gas"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:24
#: lib/block_scout_web/templates/transaction_raw_trace/index.html.eex:7
#: lib/block_scout_web/views/transaction_view.ex:265
#: lib/block_scout_web/views/transaction_view.ex:276
msgid "Raw Trace"
msgstr ""
@ -1701,11 +1692,6 @@ msgstr ""
msgid " Token Transfer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:27
msgid "There is no decompilded contracts for this address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:14
msgid " is recommended."
@ -1731,6 +1717,11 @@ msgstr ""
msgid "However, in general, the"
msgstr ""
#, elixir-format, fuzzy
#: lib/block_scout_web/templates/address_decompiled_contract/index.html.eex:27
msgid "There is no decompilded contracts for this address."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:7
msgid "This API is provided to support some rpc methods in the exact format specified for ethereum nodes, which can be found "
@ -1749,14 +1740,4 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/eth_rpc.html.eex:9
msgid "here."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:51
msgid "Constructor arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:58
msgid "External libraries"
msgstr ""
msgstr ""

@ -132,4 +132,40 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
end)
end
end
describe "GET token_transfers_csv/2" do
test "exports token transfers to csv", %{conn: conn} do
address = insert(:address)
transaction =
:transaction
|> insert(from_address: address)
|> with_block()
insert(:token_transfer, transaction: transaction, from_address: address)
insert(:token_transfer, transaction: transaction, to_address: address)
conn = get(conn, "/token_transfers_csv", %{"address_id" => to_string(address.hash)})
assert conn.resp_body |> String.split("\n") |> Enum.count() == 4
end
end
describe "GET transactions_csv/2" do
test "download csv file with transactions", %{conn: conn} do
address = insert(:address)
:transaction
|> insert(from_address: address)
|> with_block()
:transaction
|> insert(from_address: address)
|> with_block()
conn = get(conn, "/transactions_csv", %{"address_id" => to_string(address.hash)})
assert conn.resp_body |> String.split("\n") |> Enum.count() == 4
end
end
end

@ -2923,7 +2923,7 @@ defmodule Explorer.Chain do
end
@spec transaction_token_transfer_type(Transaction.t()) ::
{:erc20, TokenTransfer.t()} | {:erc721, TokenTransfer.t()} | nil
:erc20 | :erc721 | :token_transfer | nil
def transaction_token_transfer_type(
%Transaction{
status: :ok,
@ -2933,8 +2933,19 @@ defmodule Explorer.Chain do
} = transaction
) do
zero_wei = %Wei{value: Decimal.new(0)}
result = find_token_transfer_type(transaction, input, value)
transaction = Repo.preload(transaction, token_transfers: :token)
if is_nil(result) && Enum.count(transaction.token_transfers) > 0 && value == zero_wei,
do: :token_transfer,
else: result
rescue
_ -> nil
end
def transaction_token_transfer_type(_), do: nil
defp find_token_transfer_type(transaction, input, value) do
zero_wei = %Wei{value: Decimal.new(0)}
# https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/token/ERC721/ERC721.sol#L35
case {to_string(input), value} do
@ -2959,6 +2970,9 @@ defmodule Explorer.Chain do
find_erc721_token_transfer(transaction.token_transfers, {from_address, to_address})
{"0xf907fc5b" <> _params, ^zero_wei} ->
:erc20
# check for ERC 20 or for old ERC 721 token versions
{unquote(TokenTransfer.transfer_function_signature()) <> params, ^zero_wei} ->
types = [:address, {:uint, 256}]
@ -2972,34 +2986,31 @@ defmodule Explorer.Chain do
_ ->
nil
end
rescue
_ -> nil
end
def transaction_token_transfer_type(_), do: nil
defp find_erc721_token_transfer(token_transfers, {from_address, to_address}) do
token_transfer =
Enum.find(token_transfers, fn token_transfer ->
token_transfer.from_address_hash.bytes == from_address && token_transfer.to_address_hash.bytes == to_address
end)
if token_transfer, do: {:erc721, token_transfer}
if token_transfer, do: :erc721
end
defp find_erc721_or_erc20_token_transfer(token_transfers, {address, decimal_value}) do
token_transfer =
Enum.find(token_transfers, fn token_transfer ->
token_transfer.to_address_hash.bytes == address &&
(token_transfer.amount == decimal_value || token_transfer.token_id)
token_transfer.to_address_hash.bytes == address && token_transfer.amount == decimal_value
end)
if token_transfer do
case token_transfer.token do
%Token{type: "ERC-20"} -> {:erc20, token_transfer}
%Token{type: "ERC-721"} -> {:erc721, token_transfer}
%Token{type: "ERC-20"} -> :erc20
%Token{type: "ERC-721"} -> :erc721
_ -> nil
end
else
:erc20
end
end

@ -0,0 +1,119 @@
defmodule Explorer.Chain.AddressTokenTransferCsvExporter do
@moduledoc """
Exports token transfers to a csv file.
"""
alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.{Address, TokenTransfer, Transaction}
alias NimbleCSV.RFC4180
@necessity_by_association [
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional,
[token_transfers: :token] => :optional,
[token_transfers: :to_address] => :optional,
[token_transfers: :from_address] => :optional,
[token_transfers: :token_contract_address] => :optional,
:block => :required
}
]
@page_size 150
@paging_options %PagingOptions{page_size: @page_size + 1}
def export(address) do
address
|> fetch_all_transactions(@paging_options)
|> to_token_transfers()
|> to_csv_format(address)
|> dump_to_stream()
end
defp fetch_all_transactions(address, paging_options, acc \\ []) do
options = Keyword.merge(@necessity_by_association, paging_options: paging_options)
transactions =
address
|> Chain.address_to_transactions_with_rewards(options)
|> Enum.filter(fn transaction -> Enum.count(transaction.token_transfers) > 0 end)
new_acc = transactions ++ acc
case Enum.split(transactions, @page_size) do
{_transactions, [%Transaction{block_number: block_number, index: index}]} ->
new_paging_options = %{@paging_options | key: {block_number, index}}
fetch_all_transactions(address, new_paging_options, new_acc)
{_, []} ->
new_acc
end
end
defp to_token_transfers(transactions) do
transactions
|> Enum.flat_map(fn transaction ->
transaction.token_transfers
|> Enum.map(fn transfer -> %{transfer | transaction: transaction} end)
end)
end
defp dump_to_stream(transactions) do
transactions
|> RFC4180.dump_to_stream()
end
defp to_csv_format(token_transfers, address) do
row_names = [
"TxHash",
"BlockNumber",
"UnixTimestamp",
"FromAddress",
"ToAddress",
"TokenContractAddress",
"Type",
"TokenSymbol",
"TokensTransferred",
"TransactionFee",
"Status",
"ErrCode"
]
token_transfer_lists =
token_transfers
|> Stream.map(fn token_transfer ->
[
to_string(token_transfer.transaction_hash),
token_transfer.transaction.block_number,
token_transfer.transaction.block.timestamp,
token_transfer.from_address |> to_string() |> String.downcase(),
token_transfer.to_address |> to_string() |> String.downcase(),
token_transfer.token_contract_address |> to_string() |> String.downcase(),
type(token_transfer, address),
token_transfer.token.symbol,
token_transfer.amount,
fee(token_transfer.transaction),
token_transfer.transaction.status,
token_transfer.transaction.error
]
end)
Stream.concat([row_names], token_transfer_lists)
end
defp type(%TokenTransfer{from_address_hash: from_address}, %Address{hash: from_address}), do: "OUT"
defp type(%TokenTransfer{to_address_hash: to_address}, %Address{hash: to_address}), do: "IN"
defp type(_, _), do: ""
defp fee(transaction) do
transaction
|> Chain.fee(:wei)
|> case do
{:actual, value} -> value
{:maximum, value} -> "Max of #{value}"
end
end
end

@ -0,0 +1,139 @@
defmodule Explorer.Chain.AddressTransactionCsvExporter do
@moduledoc """
Exports transactions to a csv file.
"""
import Ecto.Query,
only: [
from: 2
]
alias Explorer.{Chain, Market, PagingOptions, Repo}
alias Explorer.Market.MarketHistory
alias Explorer.Chain.{Address, Transaction, Wei}
alias Explorer.ExchangeRates.Token
alias NimbleCSV.RFC4180
@necessity_by_association [
necessity_by_association: %{
[created_contract_address: :names] => :optional,
[from_address: :names] => :optional,
[to_address: :names] => :optional,
[token_transfers: :token] => :optional,
[token_transfers: :to_address] => :optional,
[token_transfers: :from_address] => :optional,
[token_transfers: :token_contract_address] => :optional,
:block => :required
}
]
@page_size 150
@paging_options %PagingOptions{page_size: @page_size + 1}
@spec export(Address.t()) :: Enumerable.t()
def export(address) do
exchange_rate = Market.get_exchange_rate(Explorer.coin()) || Token.null()
address
|> fetch_all_transactions(@paging_options)
|> to_csv_format(address, exchange_rate)
|> dump_to_stream()
end
defp fetch_all_transactions(address, paging_options, acc \\ []) do
options = Keyword.merge(@necessity_by_association, paging_options: paging_options)
transactions = Chain.address_to_transactions_with_rewards(address, options)
new_acc = transactions ++ acc
case Enum.split(transactions, @page_size) do
{_transactions, [%Transaction{block_number: block_number, index: index}]} ->
new_paging_options = %{@paging_options | key: {block_number, index}}
fetch_all_transactions(address, new_paging_options, new_acc)
{_, []} ->
new_acc
end
end
defp dump_to_stream(transactions) do
transactions
|> RFC4180.dump_to_stream()
end
defp to_csv_format(transactions, address, exchange_rate) do
row_names = [
"TxHash",
"BlockNumber",
"UnixTimestamp",
"FromAddress",
"ToAddress",
"ContractAddress",
"Type",
"Value",
"Fee",
"Status",
"ErrCode",
"CurrentPrice",
"TxDateOpeningPrice",
"TxDateClosingPrice"
]
transaction_lists =
transactions
|> Stream.map(fn transaction ->
{opening_price, closing_price} = price_at_date(transaction.block.timestamp)
[
to_string(transaction.hash),
transaction.block_number,
transaction.block.timestamp,
to_string(transaction.from_address),
to_string(transaction.to_address),
to_string(transaction.created_contract_address),
type(transaction, address),
Wei.to(transaction.value, :wei),
fee(transaction),
transaction.status,
transaction.error,
exchange_rate.usd_value,
opening_price,
closing_price
]
end)
Stream.concat([row_names], transaction_lists)
end
defp type(%Transaction{from_address_hash: from_address}, %Address{hash: from_address}), do: "OUT"
defp type(%Transaction{to_address_hash: to_address}, %Address{hash: to_address}), do: "IN"
defp type(_, _), do: ""
defp fee(transaction) do
transaction
|> Chain.fee(:wei)
|> case do
{:actual, value} -> value
{:maximum, value} -> "Max of #{value}"
end
end
defp price_at_date(datetime) do
date = DateTime.to_date(datetime)
query =
from(
mh in MarketHistory,
where: mh.date == ^date
)
case Repo.one(query) do
nil -> {nil, nil}
price -> {price.opening_price, price.closing_price}
end
end
end

@ -91,7 +91,7 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
"node",
[
Application.app_dir(:explorer, "priv/compile_solc.js"),
code,
create_source_file(code),
compiler_version,
optimize_value(optimize),
optimization_runs,
@ -171,5 +171,14 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
else
"#{value}"
end
end
defp create_source_file(source) do
{:ok, path} = Briefly.create()
File.write!(path, source)
path
end
end

@ -107,6 +107,13 @@ defmodule Explorer.SmartContract.Verifier do
|> Enum.reverse()
|> :binary.list_to_bin()
# Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst
"a265627a7a72305820" <>
<<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments ->
extracted
|> Enum.reverse()
|> :binary.list_to_bin()
<<next::binary-size(2)>> <> rest ->
do_extract_bytecode([next | extracted], rest)
end

@ -21,6 +21,14 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
constructor_arguments
end
# Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst
defp extract_constructor_arguments(
"a265627a7a72305820" <>
<<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments
) do
constructor_arguments
end
defp extract_constructor_arguments(<<_::binary-size(2)>> <> rest) do
extract_constructor_arguments(rest)
end

@ -66,6 +66,7 @@ defmodule Explorer.Mixfile do
# CSV output for benchee
{:benchee_csv, "~> 0.8.0", only: :test},
{:bypass, "~> 1.0", only: :test},
{:briefly, "~> 0.4", github: "CargoSense/briefly"},
{:comeonin, "~> 4.0"},
{:credo, "1.0.0", only: :test, runtime: false},
# For Absinthe to load data in batches
@ -91,7 +92,9 @@ defmodule Explorer.Mixfile do
{:math, "~> 0.3.0"},
{:mock, "~> 0.3.0", only: [:test], runtime: false},
{:mox, "~> 0.4", only: [:test]},
{:nimble_csv, "~> 0.6.0"},
{:poison, "~> 3.1"},
{:nimble_csv, "~> 0.6.0"},
{:postgrex, ">= 0.0.0"},
# For compatibility with `prometheus_process_collector`, which hasn't been updated yet
{:prometheus, "~> 4.0", override: true},

@ -1,6 +1,6 @@
#!/usr/bin/env node
var sourceCode = process.argv[2];
var sourceCodePath = process.argv[2];
var version = process.argv[3];
var optimize = process.argv[4];
var optimizationRuns = parseInt(process.argv[5], 10);
@ -13,6 +13,9 @@ var solc = require('solc')
var compilerSnapshot = require(compilerVersionPath);
var solc = solc.setupMethods(compilerSnapshot);
var fs = require('fs');
var sourceCode = fs.readFileSync(sourceCodePath, 'utf8');
const input = {
language: 'Solidity',
sources: {

@ -0,0 +1,72 @@
defmodule Explorer.Chain.AddressTokenTransferCsvExporterTest do
use Explorer.DataCase
alias Explorer.Chain.AddressTokenTransferCsvExporter
describe "export/1" do
test "exports token transfers to csv" do
address = insert(:address)
transaction =
:transaction
|> insert(from_address: address)
|> with_block()
token_transfer = insert(:token_transfer, transaction: transaction, from_address: address)
[result] =
address
|> AddressTokenTransferCsvExporter.export()
|> Enum.to_list()
|> Enum.drop(1)
|> Enum.map(fn [
tx_hash,
_,
block_number,
_,
timestamp,
_,
from_address,
_,
to_address,
_,
token_contract_address,
_,
type,
_,
token_symbol,
_,
tokens_transferred,
_,
transaction_fee,
_,
status,
_,
err_code,
_
] ->
%{
tx_hash: tx_hash,
block_number: block_number,
timestamp: timestamp,
from_address: from_address,
to_address: to_address,
token_contract_address: token_contract_address,
type: type,
token_symbol: token_symbol,
tokens_transferred: tokens_transferred,
transaction_fee: transaction_fee,
status: status,
err_code: err_code
}
end)
assert result.block_number == to_string(transaction.block_number)
assert result.tx_hash == to_string(transaction.hash)
assert result.from_address == token_transfer.from_address_hash |> to_string() |> String.downcase()
assert result.to_address == token_transfer.to_address_hash |> to_string() |> String.downcase()
assert result.timestamp == to_string(transaction.block.timestamp)
assert result.type == "OUT"
end
end
end

@ -0,0 +1,105 @@
defmodule Explorer.Chain.AddressTransactionCsvExporterTest do
use Explorer.DataCase
alias Explorer.Chain.{AddressTransactionCsvExporter, Wei}
describe "export/1" do
test "exports address transactions to csv" do
address = insert(:address)
transaction =
:transaction
|> insert(from_address: address)
|> with_block()
|> Repo.preload(:token_transfers)
[result] =
address
|> AddressTransactionCsvExporter.export()
|> Enum.to_list()
|> Enum.drop(1)
|> Enum.map(fn [
hash,
_,
block_number,
_,
timestamp,
_,
from_address,
_,
to_address,
_,
created_address,
_,
type,
_,
value,
_,
fee,
_,
status,
_,
error,
_,
cur_price,
_,
op_price,
_,
cl_price,
_
] ->
%{
hash: hash,
block_number: block_number,
timestamp: timestamp,
from_address: from_address,
to_address: to_address,
created_address: created_address,
type: type,
value: value,
fee: fee,
status: status,
error: error,
current_price: cur_price,
opening_price: op_price,
closing_price: cl_price
}
end)
assert result.block_number == to_string(transaction.block_number)
assert result.timestamp
assert result.created_address == to_string(transaction.created_contract_address_hash)
assert result.from_address == to_string(transaction.from_address)
assert result.to_address == to_string(transaction.to_address)
assert result.hash == to_string(transaction.hash)
assert result.type == "OUT"
assert result.value == transaction.value |> Wei.to(:wei) |> to_string()
assert result.fee
assert result.status == to_string(transaction.status)
assert result.error == to_string(transaction.error)
assert result.current_price
assert result.opening_price
assert result.closing_price
end
test "fetches all transactions" do
address = insert(:address)
1..200
|> Enum.map(fn _ ->
:transaction
|> insert(from_address: address)
|> with_block()
end)
|> Enum.count()
result =
address
|> AddressTransactionCsvExporter.export()
|> Enum.to_list()
|> Enum.drop(1)
assert Enum.count(result) == 200
end
end
end

@ -3954,7 +3954,7 @@ defmodule Explorer.ChainTest do
insert(:token_transfer, from_address: from_address, to_address: to_address, transaction: transaction)
assert {:erc721, _found_token_transfer} = Chain.transaction_token_transfer_type(transaction)
assert :erc721 = Chain.transaction_token_transfer_type(Repo.preload(transaction, token_transfers: :token))
end
test "detects erc20 token transfer" do
@ -3980,7 +3980,7 @@ defmodule Explorer.ChainTest do
amount: 8_025_000_000_000_000_000_000
)
assert {:erc20, _found_token_transfer} = Chain.transaction_token_transfer_type(transaction)
assert :erc20 = Chain.transaction_token_transfer_type(Repo.preload(transaction, token_transfers: :token))
end
end

@ -268,6 +268,20 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
assert Enum.any?(abi, fn el -> el["type"] == "constructor" end)
end
test "can compile a large file" do
path = File.cwd!() <> "/test/support/fixture/smart_contract/large_smart_contract.sol"
contract = File.read!(path)
assert {:ok, %{"abi" => abi}} =
CodeCompiler.run(
name: "HomeWorkDeployer",
compiler_version: "v0.5.9+commit.e560f70d",
code: contract,
evm_version: "constantinople",
optimize: true
)
end
end
describe "get_contract_info/1" do

File diff suppressed because one or more lines are too long

@ -0,0 +1,76 @@
pragma solidity ^0.5.9;
contract Token {
function totalSupply() public view returns (uint256 supply) {}
function balanceOf(address _owner) public view returns (uint256 balance) {}
function transfer(address _to, uint256 _value) public returns (bool success) {}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {}
function approve(address _spender, uint256 _value) public returns (bool success) {}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {}
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract StandardToken is Token {
function transfer(address _to, uint256 _value) public returns (bool success) {
//if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (balances[msg.sender] >= _value && _value > 0) {
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
} else { return false; }
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
//if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
balances[_to] += _value;
balances[_from] -= _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
} else { return false; }
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
uint256 totalTokenSupply;
}
contract TestToken is StandardToken {
/* Public variables */
string public name;
uint8 public decimals;
string public symbol;
string public version = '0.1';
constructor(
uint256 _initialAmount,
string memory _tokenName,
uint8 _decimalUnits,
string memory _tokenSymbol
) public {
balances[msg.sender] = _initialAmount;
totalTokenSupply = _initialAmount;
name = _tokenName;
decimals = _decimalUnits;
symbol = _tokenSymbol;
}
function approveAndCall(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
}

@ -49,7 +49,7 @@ defmodule Indexer.MixProject do
# JSONRPC access to Parity for `Explorer.Indexer`
{:ethereum_jsonrpc, in_umbrella: true},
# RLP encoding
{:ex_rlp, "~> 0.3"},
{:ex_rlp, "~> 0.5.2"},
# Code coverage
{:excoveralls, "~> 0.10.0", only: [:test], github: "KronicDeth/excoveralls", branch: "circle-workflows"},
# Importing to database

@ -1,6 +1,6 @@
export DISPLAY=:99.0
sh -e /etc/init.d/xvfb start
export CHROMEDRIVER_VERSION=74.0.3729.6
export CHROMEDRIVER_VERSION=`curl -s http://chromedriver.storage.googleapis.com/LATEST_RELEASE`
curl -L -O "http://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip"
unzip chromedriver_linux64.zip
sudo chmod +x chromedriver

@ -11,6 +11,7 @@
"benchee": {:hex, :benchee, "0.13.2", "30cd4ff5f593fdd218a9b26f3c24d580274f297d88ad43383afe525b1543b165", [:mix], [{:deep_merge, "~> 0.1", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm"},
"benchee_csv": {:hex, :benchee_csv, "0.8.0", "0ca094677d6e2b2f601b7ee7864b754789ef9d24d079432e5e3d6f4fb83a4d80", [:mix], [{:benchee, "~> 0.12", [hex: :benchee, optional: false]}, {:csv, "~> 2.0", [hex: :csv, optional: false]}]},
"binary": {:hex, :binary, "0.0.5", "20d816f7274ea34f1b673b4cff2fdb9ebec9391a7a68c349070d515c66b1b2cf", [:mix], []},
"briefly": {:git, "https://github.com/CargoSense/briefly.git", "2526e9674a4e6996137e066a1295ea60962712b8", []},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], []},
"bypass": {:hex, :bypass, "1.0.0", "b78b3dcb832a71aca5259c1a704b2e14b55fd4e1327ff942598b4e7d1a7ad83d", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}], "hexpm"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
@ -73,6 +74,7 @@
"mock": {:hex, :mock, "0.3.2", "e98e998fd76c191c7e1a9557c8617912c53df3d4a6132f561eb762b699ef59fa", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"},
"mox": {:hex, :mox, "0.4.0", "7f120840f7d626184a3d65de36189ca6f37d432e5d63acd80045198e4c5f7e6e", [:mix], [], "hexpm"},
"msgpax": {:hex, :msgpax, "2.2.2", "559a07806bbe5fdd31e4597455be030bd96356f7a621ca9eed832747c83bfb67", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
"nimble_csv": {:hex, :nimble_csv, "0.6.0", "a3673f26d41f986774fe6060e309615343d3cb83a6d435754d8b1fdbd5764879", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
"optimal": {:hex, :optimal, "0.3.6", "46bbf52fbbbd238cda81e02560caa84f93a53c75620f1fe19e81e4ae7b07d1dd", [:mix], [], "hexpm"},
"parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], []},

Loading…
Cancel
Save