Verify via metadata json

pull/3858/head
Victor Baranov 4 years ago committed by Viktor Baranov
parent b40758e36f
commit 51e7fd0571
  1. 4
      .dialyzer-ignore
  2. 1
      apps/block_scout_web/assets/css/_mixins.scss
  3. 1
      apps/block_scout_web/assets/css/app.scss
  4. 541
      apps/block_scout_web/assets/css/components/_dropzone.scss
  5. 4
      apps/block_scout_web/assets/css/components/_new_smart_contract.scss
  6. 1
      apps/block_scout_web/assets/js/lib/dropzone.js
  7. 36
      apps/block_scout_web/assets/js/pages/verification_form.js
  8. 11
      apps/block_scout_web/assets/package-lock.json
  9. 1
      apps/block_scout_web/assets/package.json
  10. 30
      apps/block_scout_web/assets/webpack.config.js
  11. 178
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex
  12. 49
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_via_flattened_code_controller.ex
  13. 7
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_via_json_controller.ex
  14. 22
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/contract_controller.ex
  15. 20
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  16. 22
      apps/block_scout_web/lib/block_scout_web/router.ex
  17. 35
      apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
  18. 393
      apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification/new.html.eex
  19. 314
      apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex
  20. 59
      apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex
  21. 9
      apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex
  22. 9
      apps/block_scout_web/lib/block_scout_web/templates/smart_contract/_functions.html.eex
  23. 9
      apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input.html.eex
  24. 9
      apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
  25. 5
      apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_flattened_code_view.ex
  26. 3
      apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_json_view.ex
  27. 2
      apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_view.ex
  28. 7
      apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
  29. 30
      apps/block_scout_web/lib/block_scout_web/web_router.ex
  30. 245
      apps/block_scout_web/priv/gettext/default.pot
  31. 245
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  32. 2
      apps/block_scout_web/test/block_scout_web/features/pages/contract_verify_page.ex
  33. 6
      apps/explorer/config/config.exs
  34. 69
      apps/explorer/lib/explorer/chain.ex
  35. 2
      apps/explorer/lib/explorer/chain/address.ex
  36. 11
      apps/explorer/lib/explorer/chain/smart_contract.ex
  37. 63
      apps/explorer/lib/explorer/chain/smart_contract_additional_sources.ex
  38. 8
      apps/explorer/lib/explorer/smart_contract/publisher.ex
  39. 184
      apps/explorer/lib/explorer/third_party_integrations/sourcify.ex
  40. 6
      apps/explorer/mix.exs
  41. 22
      apps/explorer/priv/repo/migrations/20201214203532_support_sourcify.exs
  42. 7
      apps/explorer/test/explorer/chain_test.exs
  43. 1
      mix.exs

@ -23,6 +23,8 @@ lib/indexer/fetcher/token_total_supply_on_demand.ex:16
lib/explorer/exchange_rates/source.ex:110
lib/explorer/exchange_rates/source.ex:113
lib/explorer/smart_contract/verifier.ex:89
lib/block_scout_web/templates/address_contract/index.html.eex:123
lib/block_scout_web/templates/address_contract/index.html.eex:149
lib/explorer/staking/stake_snapshotting.ex:15: Function do_snapshotting/7 has no local return
lib/explorer/staking/stake_snapshotting.ex:147
lib/explorer/third_party_integrations/sourcify.ex:65
lib/explorer/third_party_integrations/sourcify.ex:68

@ -95,6 +95,7 @@
&:hover {
background-color: darken($bg-color, 10%);
border-color: darken($bg-color, 10%);
color: $text-color;
text-decoration: none;
}

@ -119,6 +119,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "components/_external_link";
@import "components/_label";
@import "components/_token";
@import "components/_dropzone";
@import "theme/dark-theme";

@ -0,0 +1,541 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
@-webkit-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px);
}
30%,
70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px);
}
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px);
}
}
@-moz-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px);
}
30%,
70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px);
}
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px);
}
}
@keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px);
}
30%,
70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px);
}
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px);
}
}
@-webkit-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px);
}
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px);
}
}
@-moz-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px);
}
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px);
}
}
@keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px);
}
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px);
}
}
@-webkit-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1);
}
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
}
@-moz-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1);
}
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
}
@keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1);
}
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
}
}
.dropzone-1,
.dropzone-1 * {
box-sizing: border-box;
}
.dropzone-1 {
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px;
}
.dropzone-1.dz-clickable {
cursor: pointer;
}
.dropzone-1.dz-clickable * {
cursor: default;
}
.dropzone-1.dz-clickable .dz-message,
.dropzone-1.dz-clickable .dz-message * {
cursor: pointer;
}
.dropzone-1.dz-started .dz-message {
display: none;
}
.dropzone-1.dz-drag-hover {
border-style: solid;
}
.dropzone-1.dz-drag-hover .dz-message {
opacity: 0.5;
}
.dropzone-1 .dz-message {
text-align: center;
margin: 2em 0;
}
.dropzone-1 .dz-message .dz-button {
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
}
.dropzone-1 .dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
margin: 16px;
min-height: 100px;
}
.dropzone-1 .dz-preview:hover {
z-index: 1000;
}
.dropzone-1 .dz-preview:hover .dz-details {
opacity: 1;
}
.dropzone-1 .dz-preview.dz-file-preview .dz-image {
border-radius: 20px;
background: #999;
background: linear-gradient(to bottom, #eee, #ddd);
}
.dropzone-1 .dz-preview.dz-file-preview .dz-details {
opacity: 1;
}
.dropzone-1 .dz-preview.dz-image-preview {
background: white;
}
.dropzone-1 .dz-preview.dz-image-preview .dz-details {
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-ms-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.dropzone-1 .dz-preview .dz-remove {
font-size: 14px;
text-align: center;
display: block;
cursor: pointer;
border: none;
}
.dropzone-1 .dz-preview .dz-remove:hover {
text-decoration: underline;
}
.dropzone-1 .dz-preview:hover .dz-details {
opacity: 1;
}
.dropzone-1 .dz-preview .dz-details {
z-index: 20;
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 13px;
min-width: 100%;
max-width: 100%;
padding: 2em 1em;
text-align: center;
color: rgba(0, 0, 0, 0.9);
line-height: 150%;
}
.dropzone-1 .dz-preview .dz-details .dz-size {
margin-bottom: 1em;
font-size: 16px;
}
.dropzone-1 .dz-preview .dz-details .dz-filename {
white-space: nowrap;
}
.dropzone-1 .dz-preview .dz-details .dz-filename:hover span {
border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8);
}
.dropzone-1 .dz-preview .dz-details .dz-filename:not(:hover) {
overflow: hidden;
text-overflow: ellipsis;
}
.dropzone-1 .dz-preview .dz-details .dz-filename:not(:hover) span {
border: 1px solid transparent;
}
.dropzone-1 .dz-preview .dz-details .dz-filename span,
.dropzone-1 .dz-preview .dz-details .dz-size span {
background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em;
border-radius: 3px;
}
.dropzone-1 .dz-preview:hover .dz-image img {
-webkit-transform: scale(1.05, 1.05);
-moz-transform: scale(1.05, 1.05);
-ms-transform: scale(1.05, 1.05);
-o-transform: scale(1.05, 1.05);
transform: scale(1.05, 1.05);
-webkit-filter: blur(8px);
filter: blur(8px);
}
.dropzone-1 .dz-preview .dz-image {
border-radius: 20px;
overflow: hidden;
width: 120px;
height: 120px;
position: relative;
display: block;
z-index: 10;
}
.dropzone-1 .dz-preview .dz-image img {
display: block;
}
.dropzone-1 .dz-preview.dz-success .dz-success-mark {
-webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
}
.dropzone-1 .dz-preview.dz-error .dz-error-mark {
opacity: 1;
-webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
}
.dropzone-1 .dz-preview .dz-success-mark,
.dropzone-1 .dz-preview .dz-error-mark {
pointer-events: none;
opacity: 0;
z-index: 500;
position: absolute;
display: block;
top: 50%;
left: 50%;
margin-left: -27px;
margin-top: -27px;
}
.dropzone-1 .dz-preview .dz-success-mark svg,
.dropzone-1 .dz-preview .dz-error-mark svg {
display: block;
width: 54px;
height: 54px;
}
.dropzone-1 .dz-preview.dz-processing .dz-progress {
opacity: 1;
-webkit-transition: all 0.2s linear;
-moz-transition: all 0.2s linear;
-ms-transition: all 0.2s linear;
-o-transition: all 0.2s linear;
transition: all 0.2s linear;
}
.dropzone-1 .dz-preview.dz-complete .dz-progress {
opacity: 0;
-webkit-transition: opacity 0.4s ease-in;
-moz-transition: opacity 0.4s ease-in;
-ms-transition: opacity 0.4s ease-in;
-o-transition: opacity 0.4s ease-in;
transition: opacity 0.4s ease-in;
}
.dropzone-1 .dz-preview:not(.dz-processing) .dz-progress {
-webkit-animation: pulse 6s ease infinite;
-moz-animation: pulse 6s ease infinite;
-ms-animation: pulse 6s ease infinite;
-o-animation: pulse 6s ease infinite;
animation: pulse 6s ease infinite;
}
.dropzone-1 .dz-preview .dz-progress {
opacity: 1;
z-index: 1000;
pointer-events: none;
position: absolute;
height: 16px;
left: 50%;
top: 50%;
margin-top: -8px;
width: 80px;
margin-left: -40px;
background: rgba(255, 255, 255, 0.9);
-webkit-transform: scale(1);
border-radius: 8px;
overflow: hidden;
}
.dropzone-1 .dz-preview .dz-progress .dz-upload {
background: #333;
background: linear-gradient(to bottom, #666, #444);
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 0;
-webkit-transition: width 300ms ease-in-out;
-moz-transition: width 300ms ease-in-out;
-ms-transition: width 300ms ease-in-out;
-o-transition: width 300ms ease-in-out;
transition: width 300ms ease-in-out;
}
.dropzone-1 .dz-preview.dz-error .dz-error-message {
display: block;
}
.dropzone-1 .dz-preview.dz-error:hover .dz-error-message {
opacity: 1;
pointer-events: auto;
}
.dropzone-1 .dz-preview .dz-error-message {
pointer-events: none;
z-index: 1000;
position: absolute;
display: block;
display: none;
opacity: 0;
-webkit-transition: opacity 0.3s ease;
-moz-transition: opacity 0.3s ease;
-ms-transition: opacity 0.3s ease;
-o-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
border-radius: 8px;
font-size: 13px;
top: 130px;
left: -10px;
width: 140px;
background: #be2626;
background: linear-gradient(to bottom, #be2626, #a92222);
padding: 0.5em 1.2em;
color: white;
}
.dropzone-1 .dz-preview .dz-error-message:after {
content: '';
position: absolute;
top: -6px;
left: 64px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #be2626;
}
// custom styles
.dropzone-1 {
border-color: $primary !important;
border-style: dashed !important;
align-items: center;
justify-content: center;
display: flex;
background: rgba($primary, 0.1) !important;
}

@ -57,6 +57,10 @@ $new-smart-contract-center-column-margin-right: 30px;
display: flex;
justify-content: flex-start;
&.vertical {
display: block;
}
.radio-big {
margin-right: 20px;

@ -5,6 +5,7 @@ import humps from 'humps'
import { subscribeChannel } from '../socket'
import { createStore, connectElements } from '../lib/redux_helpers.js'
import '../app'
import Dropzone from 'dropzone'
export const initialState = {
channelDisconnected: false,
@ -27,7 +28,7 @@ export function reducer (state = initialState, action) {
}
case 'RECEIVED_VERIFICATION_RESULT': {
if (action.msg.verificationResult === 'ok') {
return window.location.replace(window.location.href.split('/contract_verifications')[0] + '/contracts')
return window.location.replace(window.location.href.split('/contract_verifications')[0].split('/verify')[0] + '/contracts')
} else {
return Object.assign({}, state, {
newForm: action.msg.verificationResult
@ -88,6 +89,7 @@ const elements = {
}
const $contractVerificationPage = $('[data-page="contract-verification"]')
const $contractVerificationChooseTypePage = $('[data-page="contract-verification-choose-type"]')
function filterNightlyBuilds (filter) {
const select = document.getElementById('smart_contract_compiler_version')
@ -136,6 +138,16 @@ if ($contractVerificationPage.length) {
})
$(function () {
if ($('#metadata-json-dropzone').length) {
var dropzone = new Dropzone('#metadata-json-dropzone', {
autoProcessQueue: false,
acceptedFiles: 'text/plain,application/json,.sol,.json',
parallelUploads: 100,
uploadMultiple: true,
addRemoveLinks: true,
params: { address_hash: $('#smart_contract_address_hash').val() }
})
}
setTimeout(function () {
$('.nightly-builds-false').trigger('click')
}, 10)
@ -188,5 +200,27 @@ if ($contractVerificationPage.length) {
$('.js-add-contract-library-wrapper').hide()
}
})
$('#verify-via-json-submit').on('click', function (e) {
if (dropzone.files.length > 0) {
dropzone.processQueue()
} else {
$('#loading').addClass('d-none')
}
})
})
} else if ($contractVerificationChooseTypePage.length) {
$('.verify-via-flattened-code').on('click', function () {
if ($(this).prop('checked')) {
$('#verify_via_flattened_code_button').show()
$('#verify_via_json_button').hide()
}
})
$('.verify-via-json').on('click', function () {
if ($(this).prop('checked')) {
$('#verify_via_flattened_code_button').hide()
$('#verify_via_json_button').show()
}
})
}

@ -16,6 +16,7 @@
"clipboard": "^2.0.4",
"core-js": "^2.6.12",
"crypto-browserify": "^3.12.0",
"dropzone": "^5.7.2",
"eth-net-props": "^1.0.33",
"highlight.js": "^10.4.0",
"https-browserify": "^1.0.0",
@ -5628,6 +5629,11 @@
"node": ">=8"
}
},
"node_modules/dropzone": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.2.tgz",
"integrity": "sha512-5t2z51DzIsWDbTpwcJIvUlwxBbvcwdCApz0yb9ecKJwG155Xm92KMEZmHW1B0MzoXOKvFwdd0nPu5cpeVcvPHQ=="
},
"node_modules/duplexer3": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
@ -23522,6 +23528,11 @@
"is-obj": "^2.0.0"
}
},
"dropzone": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.2.tgz",
"integrity": "sha512-5t2z51DzIsWDbTpwcJIvUlwxBbvcwdCApz0yb9ecKJwG155Xm92KMEZmHW1B0MzoXOKvFwdd0nPu5cpeVcvPHQ=="
},
"duplexer3": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",

@ -28,6 +28,7 @@
"clipboard": "^2.0.4",
"core-js": "^2.6.12",
"crypto-browserify": "^3.12.0",
"dropzone": "^5.7.2",
"eth-net-props": "^1.0.33",
"highlight.js": "^10.4.0",
"https-browserify": "^1.0.0",

@ -66,6 +66,34 @@ const awesompleteJs = {
]
}
const dropzoneJs = {
entry: {
dropzone: './js/lib/dropzone.js',
},
output: {
filename: '[name].min.js',
path: path.resolve(__dirname, '../priv/static/js')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
}
]
}
]
},
optimization: {
minimizer: [
new TerserJSPlugin(jsOptimizationParams),
]
}
}
const appJs =
{
entry: {
@ -183,4 +211,4 @@ const appJs =
const viewScripts = glob.sync('./js/view_specific/**/*.js').map(transpileViewScript)
module.exports = viewScripts.concat(appJs, awesompleteJs)
module.exports = viewScripts.concat(appJs, awesompleteJs, dropzoneJs)

@ -1,8 +1,12 @@
defmodule BlockScoutWeb.AddressContractVerificationController do
use BlockScoutWeb, :controller
alias BlockScoutWeb.API.RPC.ContractController
alias Explorer.Chain
alias Explorer.Chain.Events.Publisher, as: EventsPublisher
alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.{PublisherWorker, Solidity.CodeCompiler, Solidity.CompilerVersion}
alias Explorer.ThirdPartyIntegrations.Sourcify
def new(conn, %{"address_id" => address_hash_string}) do
changeset =
@ -40,6 +44,180 @@ defmodule BlockScoutWeb.AddressContractVerificationController do
send_resp(conn, 204, "")
end
def create(
conn,
%{
"address_hash" => address_hash_string,
"file" => files
}
) do
files_array = if is_map(files), do: Enum.map(files, fn {_, file} -> file end), else: []
json_files =
files_array
|> Enum.filter(fn file -> file.content_type == "application/json" end)
json_file = json_files |> Enum.at(0)
if json_file do
if Chain.smart_contract_verified?(address_hash_string) do
# ... todo: we need to return an error here
EventsPublisher.broadcast(
[{:contract_verification_result, {address_hash_string, {:error, []}, conn}}],
:on_demand
)
else
case Sourcify.check_by_address(address_hash_string) do
{:ok, _verified_status} ->
get_metadata_and_publish(address_hash_string, conn)
_ ->
verify_and_publish(address_hash_string, files_array, conn)
end
end
else
EventsPublisher.broadcast(
[{:contract_verification_result, {address_hash_string, {:error, []}, conn}}],
:on_demand
)
end
send_resp(conn, 200, "ok")
end
def create(conn, _params) do
Que.add(PublisherWorker, {"", %{}, %{}, conn})
send_resp(conn, 204, "")
end
defp verify_and_publish(address_hash_string, files_array, conn) do
case Sourcify.verify(address_hash_string, files_array) do
{:ok, _verified_status} ->
case Sourcify.check_by_address(address_hash_string) do
{:ok, _verified_status} ->
get_metadata_and_publish(address_hash_string, conn)
_ ->
EventsPublisher.broadcast(
[{:contract_verification_result, {address_hash_string, {:error, []}, conn}}],
:on_demand
)
end
_ ->
EventsPublisher.broadcast(
[{:contract_verification_result, {address_hash_string, {:error, []}, conn}}],
:on_demand
)
end
end
defp get_metadata_and_publish(address_hash_string, conn) do
case Sourcify.get_metadata(address_hash_string) do
{:ok, verification_metadata} ->
%{"params_to_publish" => params_to_publish, "abi" => abi, "secondary_sources" => secondary_sources} =
parse_params_from_sourcify(address_hash_string, verification_metadata)
ContractController.publish(conn, %{
"addressHash" => address_hash_string,
"params" => params_to_publish,
"abi" => abi,
"secondarySources" => secondary_sources
})
_ ->
EventsPublisher.broadcast(
[{:contract_verification_result, {address_hash_string, {:error, []}, conn}}],
:on_demand
)
end
end
def parse_params_from_sourcify(address_hash_string, verification_metadata) do
verification_metadata_json =
verification_metadata
|> Enum.filter(fn %{"name" => name, "content" => _content} -> name =~ ".json" end)
|> Enum.at(0)
full_params_initial = parse_json_from_sourcify_for_insertion(verification_metadata_json)
verification_metadata_sol =
verification_metadata
|> Enum.filter(fn %{"name" => name, "content" => _content} -> name =~ ".sol" end)
full_params =
verification_metadata_sol
|> Enum.reduce(full_params_initial, fn %{"name" => name, "content" => content, "path" => _path} = param,
full_params_acc ->
compilation_target_file_name = Map.get(full_params_acc, "compilation_target_file_name")
if String.downcase(name) == String.downcase(compilation_target_file_name) do
%{
"params_to_publish" => extract_primary_source_code(content, Map.get(full_params_acc, "params_to_publish")),
"abi" => Map.get(full_params_acc, "abi"),
"secondary_sources" => Map.get(full_params_acc, "secondary_sources"),
"compilation_target_file_name" => Map.get(full_params_acc, "compilation_target_file_name")
}
else
secondary_sources = [
prepare_additional_source(address_hash_string, param) | Map.get(full_params_acc, "secondary_sources")
]
%{
"params_to_publish" => Map.get(full_params_acc, "params_to_publish"),
"abi" => Map.get(full_params_acc, "abi"),
"secondary_sources" => secondary_sources,
"compilation_target_file_name" => Map.get(full_params_acc, "compilation_target_file_name")
}
end
end)
full_params
end
defp prepare_additional_source(address_hash_string, %{"name" => name, "content" => content, "path" => _path}) do
%{
"address_hash" => address_hash_string,
"file_name" => name,
"contract_source_code" => content
}
end
defp extract_primary_source_code(content, params) do
params
|> Map.put("contract_source_code", content)
end
def parse_json_from_sourcify_for_insertion(verification_metadata_json) do
%{"name" => _, "content" => content} = verification_metadata_json
content_json = Sourcify.decode_json(content)
compiler_version = "v" <> (content_json |> Map.get("compiler") |> Map.get("version"))
abi = content_json |> Map.get("output") |> Map.get("abi")
settings = Map.get(content_json, "settings")
compilation_target_file_path = settings |> Map.get("compilationTarget") |> Map.keys() |> Enum.at(0)
compilation_target_file_name = compilation_target_file_path |> String.split("/") |> Enum.at(-1)
contract_name = settings |> Map.get("compilationTarget") |> Map.get("#{compilation_target_file_path}")
optimizer = Map.get(settings, "optimizer")
params =
%{}
|> Map.put("name", contract_name)
|> Map.put("compiler_version", compiler_version)
|> Map.put("evm_version", Map.get(settings, "evmVersion"))
|> Map.put("optimization", Map.get(optimizer, "enabled"))
|> Map.put("optimization_runs", Map.get(optimizer, "runs"))
|> Map.put("external_libraries", Map.get(settings, "libraries"))
|> Map.put("verified_via_sourcify", true)
%{
"params_to_publish" => params,
"abi" => abi,
"compilation_target_file_name" => compilation_target_file_name,
"secondary_sources" => []
}
end
def parse_optimization_runs(%{"runs" => runs}) do
case Integer.parse(runs) do
{integer, ""} -> integer

@ -0,0 +1,49 @@
defmodule BlockScoutWeb.AddressContractVerificationViaFlattenedCodeController do
use BlockScoutWeb, :controller
alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.{PublisherWorker, Solidity.CodeCompiler, Solidity.CompilerVersion}
def new(conn, %{"address_id" => address_hash_string}) do
changeset =
SmartContract.changeset(
%SmartContract{address_hash: address_hash_string},
%{}
)
compiler_versions =
case CompilerVersion.fetch_versions() do
{:ok, compiler_versions} ->
compiler_versions
{:error, _} ->
[]
end
render(conn, "new.html",
changeset: changeset,
compiler_versions: compiler_versions,
evm_versions: CodeCompiler.allowed_evm_versions(),
address_hash: address_hash_string
)
end
def create(
conn,
%{
"smart_contract" => smart_contract,
"external_libraries" => external_libraries
}
) do
Que.add(PublisherWorker, {smart_contract["address_hash"], smart_contract, external_libraries, conn})
send_resp(conn, 204, "")
end
def parse_optimization_runs(%{"runs" => runs}) do
case Integer.parse(runs) do
{integer, ""} -> integer
_ -> 200
end
end
end

@ -0,0 +1,7 @@
defmodule BlockScoutWeb.AddressContractVerificationViaJsonController do
use BlockScoutWeb, :controller
def new(conn, %{"address_id" => address_hash_string}) do
render(conn, "new.html", address_hash: address_hash_string)
end
end

@ -3,6 +3,7 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
alias BlockScoutWeb.API.RPC.Helpers
alias Explorer.Chain
alias Explorer.Chain.Events.Publisher, as: EventsPublisher
alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.Publisher
@ -42,6 +43,27 @@ defmodule BlockScoutWeb.API.RPC.ContractController do
end
end
def publish(conn, %{"addressHash" => address_hash, "params" => params, "abi" => abi} = input) do
params =
if Map.has_key?(input, "secondarySources") do
params
|> Map.put("secondary_sources", Map.get(input, "secondarySources"))
else
params
end
result =
case Publisher.publish_smart_contract(address_hash, params, abi) do
{:ok, _contract} = result ->
result
{:error, changeset} ->
{:error, changeset}
end
EventsPublisher.broadcast([{:contract_verification_result, {address_hash, result, conn}}], :on_demand)
end
def listcontracts(conn, params) do
with pagination_options <- Helpers.put_pagination_options(%{}, params),
{:params, {:ok, options}} <- {:params, add_filters(pagination_options, params)} do

@ -4,7 +4,13 @@ defmodule BlockScoutWeb.Notifier do
"""
alias Absinthe.Subscription
alias BlockScoutWeb.{AddressContractVerificationView, Endpoint}
alias BlockScoutWeb.{
AddressContractVerificationViaFlattenedCodeView,
AddressContractVerificationViaJsonView,
Endpoint
}
alias Explorer.{Chain, Market, Repo}
alias Explorer.Chain.{Address, InternalTransaction, TokenTransfer, Transaction}
alias Explorer.Chain.Supply.RSK
@ -40,6 +46,8 @@ defmodule BlockScoutWeb.Notifier do
def handle_event(
{:chain_event, :contract_verification_result, :on_demand, {address_hash, contract_verification_result, conn}}
) do
verification_from_json_upload? = Map.has_key?(conn.params, "file")
contract_verification_result =
case contract_verification_result do
{:ok, _} = result ->
@ -55,8 +63,16 @@ defmodule BlockScoutWeb.Notifier do
[]
end
view =
if verification_from_json_upload? do
AddressContractVerificationViaJsonView
else
AddressContractVerificationViaFlattenedCodeView
end
result =
View.render_to_string(AddressContractVerificationView, "new.html",
view
|> View.render_to_string("new.html",
changeset: changeset,
compiler_versions: compiler_versions,
evm_versions: CodeCompiler.allowed_evm_versions(),

@ -75,6 +75,28 @@ defmodule BlockScoutWeb.Router do
end
end
# if path != api_path do
# scope to_string(api_path) <> "/verify_smart_contract" do
# pipe_through(:api)
# if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
# post("/contract_verifications", BlockScoutWeb.AddressContractVerificationController, :create)
# else
# post("/contract_verifications", BlockScoutWeb.AddressContractVerificationViaFlattenedCodeController, :create)
# end
# end
# else
# scope "/verify_smart_contract" do
# pipe_through(:api)
# if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
# post("/contract_verifications", BlockScoutWeb.AddressContractVerificationController, :create)
# else
# post("/contract_verifications", BlockScoutWeb.AddressContractVerificationViaFlattenedCodeController, :create)
# end
# end
# end
if Application.get_env(:block_scout_web, WebRouter)[:enabled] do
forward("/", BlockScoutWeb.WebRouter)
else

@ -2,6 +2,8 @@
<% minimal_proxy_template = Chain.get_minimal_proxy_template(@address.hash) %>
<% metadata_for_verification = minimal_proxy_template || Chain.get_address_verified_twin_contract(@address.hash).verified_contract %>
<% smart_contract_verified = BlockScoutWeb.AddressView.smart_contract_verified?(@address) %>
<% additional_sources_from_twin = Chain.get_address_verified_twin_contract(@address.hash).additional_sources %>
<% additional_sources = if smart_contract_verified, do: @address.smart_contract_additional_sources, else: additional_sources_from_twin %>
<section class="container">
<%= render BlockScoutWeb.AddressView, "overview.html", assigns %>
@ -24,6 +26,14 @@
<% end %>
<%= if smart_contract_verified || (!smart_contract_verified && metadata_for_verification) do %>
<% target_contract = if smart_contract_verified, do: @address.smart_contract, else: metadata_for_verification %>
<%= if @address.smart_contract.verified_via_sourcify && smart_contract_verified do %>
<div class="mb-4">
<i style="color: #f7b32b;" class="fa fa-info-circle"></i><span> <%= gettext("This contract has been verified via Sourcify.") %>
<a data-test="external_url" href=<%= sourcify_repo_url(@address.hash) %> target="_blank">
View contract in Sourcify repository <span class="external-token-icon"><%= render BlockScoutWeb.IconsView, "_external_link.html" %></span>
</a>
</div>
<% end %>
<div class="mb-4">
<dl class="row">
<dt class="col-md-2 text-muted"><%= gettext "Contract name:" %></dt>
@ -73,6 +83,22 @@
</div>
</section>
<%= if target_contract.verified_via_sourcify do %>
<%= Enum.map(additional_sources, fn additional_source -> %>
<section>
<div class="d-flex justify-content-between align-items-baseline">
<h3><%= additional_source.file_name %></h3>
<button type="button" class="btn-line" id="button" data-toggle="tooltip" data-placement="top" data-clipboard-text="<%= additional_source.contract_source_code %>" aria-label="Copy Contract Source Code">
<%= gettext "Copy Source Code" %>
</button>
</div>
<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(additional_source.contract_source_code, additional_source.inserted_at) do %><div data-line-number="<%= number %>"><%= line %></div><% end %></code></pre>
</div>
</section>
<% end)%>
<% end %>
<section>
<div class="d-flex justify-content-between align-items-baseline">
<h3><%= gettext "Contract ABI" %></h3>
@ -126,9 +152,16 @@
</div>
<% else %>
<%= if !smart_contract_verified do %>
<% path =
if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
address_verify_contract_path(@conn, :new, @address.hash)
else
address_verify_contract_via_flattened_code_path(@conn, :new, @address.hash)
end
%>
<%= link(
gettext("Verify & Publish"),
to: address_verify_contract_path(@conn, :new, @address.hash),
to: path,
class: "button button-primary button-sm float-right ml-3",
"data-test": "verify_and_publish"
) %>

@ -1,13 +1,4 @@
<% metadata_for_verification = Chain.get_address_verified_twin_contract(@address_hash).verified_contract %>
<% contract_name_value = if metadata_for_verification, do: metadata_for_verification.name, else: "" %>
<% optimization_runs_value = if metadata_for_verification, do: metadata_for_verification.optimization_runs, else: "200" %>
<% optimization = if metadata_for_verification, do: metadata_for_verification.optimization, else: true %>
<% evm_version = if metadata_for_verification, do: metadata_for_verification.evm_version, else: "default" %>
<% compiler_version = if metadata_for_verification, do: metadata_for_verification.compiler_version, else: "latest" %>
<% contract_source_code_value = if metadata_for_verification, do: metadata_for_verification.contract_source_code, else: "" %>
<% fetch_constructor_arguments_automatically = if metadata_for_verification, do: true, else: false %>
<% display_constructor_arguments_text_area = if fetch_constructor_arguments_automatically, do: "none", else: "block" %>
<section data-page="contract-verification" class="container new-smart-contract-container">
<section data-page="contract-verification-choose-type" class="container new-smart-contract-container">
<div data-selector="channel-disconnected-message" style="display: none;">
<div data-selector="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost" %></a>
@ -35,362 +26,31 @@
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :name, gettext("Contract Name") %>
<%= label f, "Verification via" %>
<div class="center-column">
<%= text_input f, :name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block", "data-test": "contract_name", value: contract_name_value %>
<%= error_tag f, :name, id: "contract-name-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">Must match the name specified in the code. For example, in <span class="tooltip-quote">contract MyContract {..}</span> <strong>MyContract</strong> is the contract name.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, "Include nightly builds" %>
<div class="center-column">
<div class="form-radios-group">
<div class="radio-big">
<%= radio_button f, :nightly_builds, false, checked: true, class: "form-check-input nightly-builds-false" %>
<div class="radio-icon"></div>
<%= label :nightly_builds, :false, gettext("No"), class: "radio-text" %>
</div>
<div class="radio-big">
<%= radio_button f, :nightly_builds, true, class: "form-check-input nightly-builds-true", "aria-describedby": "nightly_builds-help-block" %>
<div class="radio-icon"></div>
<%= label :nightly_builds, :true, gettext("Yes"), class: "radio-text" %>
</div>
</div>
<%= error_tag f, :nightly_builds, id: "nightly_builds-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">Select yes if you want to show nightly builds.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :compiler_version, gettext("Compiler") %>
<div class="center-column">
<%= select f, :compiler_version, @compiler_versions, class: "form-control border-rounded", selected: compiler_version, "aria-describedby": "compiler-help-block" %>
<%= error_tag f, :compiler_version, id: "compiler-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">The compiler version is specified in <span class="tooltip-quote">pragma solidity X.X.X</span>. Use the compiler version rather than the nightly build. If using the Solidity compiler, run <span class="tooltip-quote">solc —version</span> to check.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :evm_version, :evm_version, gettext("EVM Version") %>
<div class="center-column">
<%= select f, :evm_version, @evm_versions, class: "form-control border-rounded", selected: evm_version, "aria-describedby": "evm-version-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip">The EVM version the contract is written for. If the bytecode does not match the version, we try to verify using the latest EVM version. <a href="https://forum.poa.network/t/smart-contract-verification-evm-version-details/2318" target="_blank">EVM version details</a>.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, "Optimization" %>
<div class="center-column">
<div class="form-radios-group">
<div class="radio-big">
<%= radio_button f, :optimization, false, checked: !optimization, class: "form-check-input optimization-false" %>
<div class="form-radios-group vertical">
<div class="radio-big mb-3">
<%= radio_button f, :verify_via, true, checked: true, class: "form-check-input verify-via-flattened-code", "aria-describedby": "verify_via-help-block" %>
<div class="radio-icon"></div>
<%= label :smart_contract_optimization, :false, gettext("No"), class: "radio-text" %>
<%= label :verify_via, :true, gettext("Flattened source code"), class: "radio-text" %>
</div>
<div class="radio-big">
<%= radio_button f, :optimization, true, checked: optimization, class: "form-check-input optimization-true", "aria-describedby": "optimization-help-block" %>
<%= radio_button f, :verify_via, false, class: "form-check-input verify-via-json" %>
<div class="radio-icon"></div>
<%= label :smart_contract_optimization, :true, gettext("Yes"), class: "radio-text" %>
<%= label :verify_via, :false, gettext("Sources and metadata JSON file"), class: "radio-text" %>
</div>
</div>
<%= error_tag f, :optimization, id: "optimization-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">If you enabled optimization during compilation, select yes.</div>
</div>
</div>
<div class="smart-contract-form-group optimization-runs">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :name, gettext("Optimization runs") %>
<div class="center-column">
<%= text_input f, :optimization_runs, value: 200, class: "form-control border-rounded", "aria-describedby": "optimization-runs-help-block", "data-test": "optimization-runs", value: optimization_runs_value %>
<%= error_tag f, :verify_via, id: "verify_via-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :contract_source_code, gettext("Enter the Solidity Contract Code") %>
<div class="center-column">
<%= textarea f, :contract_source_code, class: "form-control border-rounded monospace", rows: 3, "aria-describedby": "contract-source-code-help-block", value: contract_source_code_value %>
<%= error_tag f, :contract_source_code, id: "contract-source-code-help-block", class: "text-danger form-error", "data-test": "contract-source-code-error" %>
</div>
<div class="smart-contract-form-group-tooltip">We recommend using flattened code. This is necessary if your code utilizes a library or inherits dependencies. Use the <a href="https://github.com/poanetwork/solidity-flattener" target="_blank">POA solidity flattener or the <a href="https://www.npmjs.com/package/truffle-flattener" target="_blank">truffle flattener</a>.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, "Try to fetch contructor arguments automatically" %>
<div class="center-column">
<div class="form-radios-group">
<div class="radio-big">
<%= radio_button f, :autodetect_contructor_args, false, checked: !fetch_constructor_arguments_automatically, class: "form-check-input autodetectfalse" %>
<div class="radio-icon"></div>
<%= label :autodetect_contructor_args, :false, gettext("No"), class: "radio-text" %>
</div>
<div class="radio-big">
<%= radio_button f, :autodetect_contructor_args, true, checked: fetch_constructor_arguments_automatically, class: "form-check-input autodetecttrue", "aria-describedby": "autodetect_contructor_args-help-block" %>
<div class="radio-icon"></div>
<%= label :autodetect_contructor_args, :true, gettext("Yes"), class: "radio-text" %>
</div>
</div>
<%= error_tag f, :autodetect_contructor_args, id: "autodetect_contructor_args-help-block", class: "text-danger form-error" %>
</div>
</div>
</div>
<div class="smart-contract-form-group constructor-arguments" style="display: <%= display_constructor_arguments_text_area %>">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :contructor_arguments, gettext("ABI-encoded Constructor Arguments (if required by the contract)") %>
<div class="center-column">
<%= textarea f, :constructor_arguments, class: "form-control border-rounded monospace", rows: 3, "aria-describedby": "contract-constructor-arguments-help-block" %>
<%= error_tag f, :constructor_arguments, id: "contract-constructor-arguments-help-block", class: "text-danger form-error", "data-test": "contract-constructor-arguments-error" %>
</div>
<div class="smart-contract-form-group-tooltip">Add arguments in <a href="https://solidity.readthedocs.io/en/develop/abi-spec.html" target="_blank">ABI hex encoded form</a>. Constructor arguments are written right to left, and will be found at the end of the input created bytecode. They may also be <a href="https://abi.hashex.org/" target="_blank">parsed here.</a></div>
</div>
</div>
<div class="add-contract-libraries-wrapper">
<span class="btn-line js-btn-add-contract-libraries">Add Contract Libraries</span>
</div>
<div class="smart-contract-libraries-wrapper js-smart-contract-libraries-wrapper">
<h2 class="smart-contract-title margin-bottom-md"><%= gettext "Contract Libraries" %></h2>
<div class="contract-library-form-group js-contract-library-form-group active">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library1, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library1_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip">A library name called in the .sol file. Multiple libraries (up to 10) may be added for each contract. Click the Add Library button to add an additional one.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library1, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library1_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip">The 0x library address. This can be found in the generated json file or Truffle output (if using truffle).</div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library2, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library2_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library2, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library2_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library3, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library3_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library3, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library3_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library4, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library4_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library4, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library4_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library5, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library5_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library5, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library5_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library6, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library6_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library6, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library6_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library7, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library7_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library7, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library7_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library8, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library8_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library8, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library8_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library9, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library9_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library9, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library9_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library10, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library10_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :library10, gettext("Library Address") %>
<div class="center-column">
<%= text_input f, :library10_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="add-contract-library-wrapper js-add-contract-library-wrapper">
<span class="btn-line js-btn-add-contract-library">Add Library</span>
<div class="smart-contract-form-group-tooltip">Choose a smart-contract verification method. Currently, Blockscout supports 2 methods:<br/>
1. Verification through flattened source code. <span
data-toggle="tooltip"
data-placement="top"
data-html="true"
data-template="<div class='tooltip' role='tooltip'><div class='arrow'></div><div class='tooltip-inner'></div></div>"
title="If using a flat file for contract verification, you can use the POA Solidity flattener or the Truffle flattener">
<i style="color: #f7b32b;" class="fa fa-info-circle ml-1" data-test="token-bridge-supply"></i></span><br/>
2. Verification through raw source files and standard JSON file(s) with metadata from the Solidity contract compilation process.</div>
</div>
</div>
@ -408,8 +68,21 @@
</span>
<%= gettext("Loading....") %>
</button>
<%= submit gettext("Verify & publish"), class: "btn-full-primary mr-2", "data-button-loading": "animation" %>
<%= reset gettext("Reset"), class: "btn-line mr-2 js-smart-contract-form-reset" %>
<%= link(
gettext("Next"),
to: address_verify_contract_via_flattened_code_path(@conn, :new, @address_hash),
id: "verify_via_flattened_code_button",
class: "btn-full-primary mr-2",
"data-button-loading": "animation"
) %>
<%= link(
gettext("Next"),
to: address_verify_contract_via_json_path(@conn, :new, @address_hash),
id: "verify_via_json_button",
class: "btn-full-primary mr-2",
style: "display: none;",
"data-button-loading": "animation"
) %>
<%=
link(
gettext("Cancel"),

@ -0,0 +1,314 @@
<% metadata_for_verification = Chain.get_address_verified_twin_contract(@address_hash).verified_contract %>
<% contract_name_value = if metadata_for_verification, do: metadata_for_verification.name, else: "" %>
<% optimization_runs_value = if metadata_for_verification, do: metadata_for_verification.optimization_runs, else: "200" %>
<% optimization = if metadata_for_verification, do: metadata_for_verification.optimization, else: true %>
<% evm_version = if metadata_for_verification, do: metadata_for_verification.evm_version, else: "default" %>
<% compiler_version = if metadata_for_verification, do: metadata_for_verification.compiler_version, else: "latest" %>
<% contract_source_code_value = if metadata_for_verification, do: metadata_for_verification.contract_source_code, else: "" %>
<% fetch_constructor_arguments_automatically = if metadata_for_verification, do: true, else: false %>
<% display_constructor_arguments_text_area = if fetch_constructor_arguments_automatically, do: "none", else: "block" %>
<section data-page="contract-verification" class="container new-smart-contract-container">
<div data-selector="channel-disconnected-message" style="display: none;">
<div data-selector="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost" %></a>
</div>
</div>
<div class="new-smart-contract-form">
<h1 class="smart-contract-title"><%= gettext "New Smart Contract Verification" %></h1>
<%= form_for @changeset,
address_contract_verification_path(@conn, :create),
[],
fn f -> %>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :address_hash, gettext("Contract Address") %>
<div class="center-column">
<%= text_input f, :address_hash, class: "form-control border-rounded", "aria-describedby": "contract-address-help-block", readonly: true %>
<%= error_tag f, :address_hash, id: "contract-address-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">The 0x address supplied on contract creation.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :name, gettext("Contract Name") %>
<div class="center-column">
<%= text_input f, :name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block", "data-test": "contract_name", value: contract_name_value %>
<%= error_tag f, :name, id: "contract-name-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">Must match the name specified in the code. For example, in <span class="tooltip-quote">contract MyContract {..}</span> <strong>MyContract</strong> is the contract name.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, "Include nightly builds" %>
<div class="center-column">
<div class="form-radios-group">
<div class="radio-big">
<%= radio_button f, :nightly_builds, false, checked: true, class: "form-check-input nightly-builds-false" %>
<div class="radio-icon"></div>
<%= label :nightly_builds, :false, gettext("No"), class: "radio-text" %>
</div>
<div class="radio-big">
<%= radio_button f, :nightly_builds, true, class: "form-check-input nightly-builds-true", "aria-describedby": "nightly_builds-help-block" %>
<div class="radio-icon"></div>
<%= label :nightly_builds, :true, gettext("Yes"), class: "radio-text" %>
</div>
</div>
<%= error_tag f, :nightly_builds, id: "nightly_builds-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">Select yes if you want to show nightly builds.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :compiler_version, gettext("Compiler") %>
<div class="center-column">
<%= select f, :compiler_version, @compiler_versions, class: "form-control border-rounded", selected: compiler_version, "aria-describedby": "compiler-help-block" %>
<%= error_tag f, :compiler_version, id: "compiler-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">The compiler version is specified in <span class="tooltip-quote">pragma solidity X.X.X</span>. Use the compiler version rather than the nightly build. If using the Solidity compiler, run <span class="tooltip-quote">solc —version</span> to check.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :evm_version, :evm_version, gettext("EVM Version") %>
<div class="center-column">
<%= select f, :evm_version, @evm_versions, class: "form-control border-rounded", selected: evm_version, "aria-describedby": "evm-version-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip">The EVM version the contract is written for. If the bytecode does not match the version, we try to verify using the latest EVM version. <a href="https://forum.poa.network/t/smart-contract-verification-evm-version-details/2318" target="_blank">EVM version details</a>.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, "Optimization" %>
<div class="center-column">
<div class="form-radios-group">
<div class="radio-big">
<%= radio_button f, :optimization, false, checked: !optimization, class: "form-check-input optimization-false" %>
<div class="radio-icon"></div>
<%= label :smart_contract_optimization, :false, gettext("No"), class: "radio-text" %>
</div>
<div class="radio-big">
<%= radio_button f, :optimization, true, checked: optimization, class: "form-check-input optimization-true", "aria-describedby": "optimization-help-block" %>
<div class="radio-icon"></div>
<%= label :smart_contract_optimization, :true, gettext("Yes"), class: "radio-text" %>
</div>
</div>
<%= error_tag f, :optimization, id: "optimization-help-block", class: "text-danger form-error" %>
</div>
<div class="smart-contract-form-group-tooltip">If you enabled optimization during compilation, select yes.</div>
</div>
</div>
<div class="smart-contract-form-group optimization-runs">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :name, gettext("Optimization runs") %>
<div class="center-column">
<%= text_input f, :optimization_runs, value: 200, class: "form-control border-rounded", "aria-describedby": "optimization-runs-help-block", "data-test": "optimization-runs", value: optimization_runs_value %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :contract_source_code, gettext("Enter the Solidity Contract Code") %>
<div class="center-column">
<%= textarea f, :contract_source_code, class: "form-control border-rounded monospace", rows: 3, "aria-describedby": "contract-source-code-help-block", value: contract_source_code_value %>
<%= error_tag f, :contract_source_code, id: "contract-source-code-help-block", class: "text-danger form-error", "data-test": "contract-source-code-error" %>
</div>
<div class="smart-contract-form-group-tooltip">We recommend using flattened code. This is necessary if your code utilizes a library or inherits dependencies. Use the <a href="https://github.com/poanetwork/solidity-flattener" target="_blank">POA solidity flattener or the <a href="https://www.npmjs.com/package/truffle-flattener" target="_blank">truffle flattener</a>.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, "Try to fetch contructor arguments automatically" %>
<div class="center-column">
<div class="form-radios-group">
<div class="radio-big">
<%= radio_button f, :autodetect_contructor_args, false, checked: !fetch_constructor_arguments_automatically, class: "form-check-input autodetectfalse" %>
<div class="radio-icon"></div>
<%= label :autodetect_contructor_args, :false, gettext("No"), class: "radio-text" %>
</div>
<div class="radio-big">
<%= radio_button f, :autodetect_contructor_args, true, checked: fetch_constructor_arguments_automatically, class: "form-check-input autodetecttrue", "aria-describedby": "autodetect_contructor_args-help-block" %>
<div class="radio-icon"></div>
<%= label :autodetect_contructor_args, :true, gettext("Yes"), class: "radio-text" %>
</div>
</div>
<%= error_tag f, :autodetect_contructor_args, id: "autodetect_contructor_args-help-block", class: "text-danger form-error" %>
</div>
</div>
</div>
<div class="smart-contract-form-group constructor-arguments" style="display: <%= display_constructor_arguments_text_area %>">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :contructor_arguments, gettext("ABI-encoded Constructor Arguments (if required by the contract)") %>
<div class="center-column">
<%= textarea f, :constructor_arguments, class: "form-control border-rounded monospace", rows: 3, "aria-describedby": "contract-constructor-arguments-help-block" %>
<%= error_tag f, :constructor_arguments, id: "contract-constructor-arguments-help-block", class: "text-danger form-error", "data-test": "contract-constructor-arguments-error" %>
</div>
<div class="smart-contract-form-group-tooltip">Add arguments in <a href="https://solidity.readthedocs.io/en/develop/abi-spec.html" target="_blank">ABI hex encoded form</a>. Constructor arguments are written right to left, and will be found at the end of the input created bytecode. They may also be <a href="https://abi.hashex.org/" target="_blank">parsed here.</a></div>
</div>
</div>
<div class="add-contract-libraries-wrapper">
<span class="btn-line js-btn-add-contract-libraries">Add Contract Libraries</span>
</div>
<div class="smart-contract-libraries-wrapper js-smart-contract-libraries-wrapper">
<h2 class="smart-contract-title margin-bottom-md"><%= gettext "Contract Libraries" %></h2>
<div class="contract-library-form-group js-contract-library-form-group active">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library1, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library1_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip">A library name called in the .sol file. Multiple libraries (up to 5) may be added for each contract. Click the Add Library button to add an additional one.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library1, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library1_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip">The 0x library address. This can be found in the generated json file or Truffle output (if using truffle).</div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library2, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library2_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library2, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library2_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library3, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library3_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library3, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library3_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library4, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library4_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library4, gettext("Library Address") %>
<div class="center-column">
<%= text_input :external_libraries, :library4_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="contract-library-form-group js-contract-library-form-group">
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label :external_libraries, :library5, gettext("Library Name") %>
<div class="center-column">
<%= text_input :external_libraries, :library5_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<%= label f, :library5, gettext("Library Address") %>
<div class="center-column">
<%= text_input f, :library5_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
</div>
<div class="smart-contract-form-group-tooltip"></div>
</div>
</div>
</div>
<div class="add-contract-library-wrapper js-add-contract-library-wrapper">
<span class="btn-line js-btn-add-contract-library">Add Library</span>
</div>
</div>
<div class="smart-contract-form-buttons">
<button
class="position-absolute w-118 btn-full-primary d-none mr-2"
disabled="true"
id="loading"
name="button"
type="button"
>
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading....") %>
</button>
<%= submit gettext("Verify & publish"), class: "btn-full-primary mr-2", "data-button-loading": "animation" %>
<%= reset gettext("Reset"), class: "btn-line mr-2 js-smart-contract-form-reset" %>
<%=
link(
gettext("Cancel"),
class: "btn-no-border",
to: address_contract_path(@conn, :index, @address_hash)
)
%>
</div>
<% end %>
</div>
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/verification-form.js") %>"></script>
</section>

@ -0,0 +1,59 @@
<section data-page="contract-verification" class="container new-smart-contract-container">
<div data-selector="channel-disconnected-message" style="display: none;">
<div data-selector="reload-button" class="alert alert-danger">
<a href="#" class="alert-link"><%= gettext "Connection Lost" %></a>
</div>
</div>
<div class="new-smart-contract-form">
<h1 class="smart-contract-title"><%= gettext "New Smart Contract Verification" %></h1>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<label for="smart_contract_address_hash"><%= gettext("Contract Address") %></label>
<div class="center-column">
<input aria-describedby="contract-address-help-block" class="form-control border-rounded" id="smart_contract_address_hash" name="smart_contract[address_hash]" type="text" value=<%= @address_hash %> readonly="">
</div>
<div class="smart-contract-form-group-tooltip">The 0x address supplied on contract creation.</div>
</div>
</div>
<div class="smart-contract-form-group">
<div class="smart-contract-form-group-inner-wrapper">
<label for="smart_contract_metadata_json"><%= gettext("Sources and Metadata JSON") %></label>
<div class="center-column">
<form action="<%= address_contract_verification_path(@conn, :create) %>" class="dropzone-1" id="metadata-json-dropzone" method="post">
<button class="dz-message btn-full-primary"><%= gettext("Drop sources and metadata JSON file or click here") %></button>
</form>
</div>
<div class="smart-contract-form-group-tooltip">Drop all Solidity contract source files and JSON metadata file(s) created during contract compilation into the drop zone.</div>
</div>
</div>
<div class="smart-contract-form-buttons">
<button
class="position-absolute w-118 btn-full-primary d-none mr-2"
disabled="true"
id="loading"
name="button"
type="button"
>
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading....") %>
</button>
<button id="verify-via-json-submit" class="btn-full-primary mr-2" data-button-loading="animation"><%= gettext("Verify & publish") %></button>
<%= reset gettext("Reset"), class: "btn-line mr-2 js-smart-contract-form-reset" %>
<%=
link(
gettext("Cancel"),
class: "btn-no-border",
to: address_contract_path(@conn, :index, @address_hash)
)
%>
</div>
</div>
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/verification-form.js") %>"></script>
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/dropzone.min.js") %>"></script>
</section>

@ -6,7 +6,14 @@
<%= gettext "To see accurate decoded input data, the contract must be verified." %>
<%= case @log.transaction do %>
<% %{to_address: %{hash: hash}} -> %>
<%= gettext "Verify the contract " %><a href="<%= address_verify_contract_path(@conn, :new, hash)%>"><%= gettext "here" %></a>
<% path =
if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
address_verify_contract_path(@conn, :new, hash)
else
address_verify_contract_via_flattened_code_path(@conn, :new, hash)
end
%>
<%= gettext "Verify the contract " %><a href="<%= path %>"><%= gettext "here" %></a>
<% _ -> %>
<%= nil %>
<% end %>

@ -5,12 +5,19 @@
<%= if minimal_proxy_template do %>
<%= render BlockScoutWeb.CommonComponentsView, "_minimal_proxy_pattern.html", address_hash: metadata_for_verification.address_hash, conn: @conn %>
<% else %>
<% path =
if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
address_verify_contract_path(@conn, :new, @address.hash)
else
address_verify_contract_via_flattened_code_path(@conn, :new, @address.hash)
end
%>
<div class="mb-4">
<%= render BlockScoutWeb.CommonComponentsView, "_info.html" %><span> <%= gettext("Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB") %> <%= link(
metadata_for_verification.address_hash,
to: address_contract_path(@conn, :index, metadata_for_verification.address_hash)) %>.<br/> <%= gettext("All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with") %> <%= link(
gettext("Verify & Publish"),
to: address_verify_contract_path(@conn, :new, @address.hash)
to: path
) %> <%= gettext("page") %></span>
</div>
<% end %>

@ -8,7 +8,14 @@
<%= gettext "To see accurate decoded input data, the contract must be verified." %>
<%= case @transaction do %>
<% %{to_address: %{hash: hash}} -> %>
<%= gettext "Verify the contract " %><a href="<%= address_verify_contract_path(@conn, :new, hash)%>"><%= gettext "here" %></a>
<% path =
if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
address_verify_contract_path(@conn, :new, hash)
else
address_verify_contract_via_flattened_code_path(@conn, :new, hash)
end
%>
<%= gettext "Verify the contract " %><a href="<%= path %>"><%= gettext "here" %></a>
<% _ -> %>
<%= nil %>
<% end %>

@ -6,7 +6,14 @@
<%= gettext "To see accurate decoded input data, the contract must be verified." %>
<%= case @transaction do %>
<% %{to_address: %{hash: hash}} -> %>
<%= gettext "Verify the contract " %><a href="<%= address_verify_contract_path(@conn, :new, hash)%>"><%= gettext "here" %></a>
<% path =
if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
address_verify_contract_path(@conn, :new, hash)
else
address_verify_contract_via_flattened_code_path(@conn, :new, hash)
end
%>
<%= gettext "Verify the contract " %><a href="<%= path %>"><%= gettext "here" %></a>
<% _ -> %>
<%= nil %>
<% end %>

@ -0,0 +1,5 @@
defmodule BlockScoutWeb.AddressContractVerificationViaFlattenedCodeView do
use BlockScoutWeb, :view
alias Explorer.Chain
end

@ -0,0 +1,3 @@
defmodule BlockScoutWeb.AddressContractVerificationViaJsonView do
use BlockScoutWeb, :view
end

@ -1,5 +1,3 @@
defmodule BlockScoutWeb.AddressContractVerificationView do
use BlockScoutWeb, :view
alias Explorer.Chain
end

@ -118,4 +118,11 @@ defmodule BlockScoutWeb.AddressContractView do
def contract_creation_code(%Address{contract_code: contract_code}) do
{:ok, contract_code}
end
def sourcify_repo_url(address_hash) do
checksummed_hash = Address.checksum(address_hash)
chain_id = Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:chain_id]
repo_url = Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:repo_url]
repo_url <> chain_id <> "/" <> checksummed_hash <> "/"
end
end

@ -126,6 +126,36 @@ defmodule BlockScoutWeb.WebRouter do
as: :verify_contract
)
# if Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled] do
# resources(
# "/contract_verifications",
# AddressContractVerificationController,
# only: [:new],
# as: :verify_contract
# )
# else
# resources(
# "/contract_verifications",
# AddressContractVerificationViaFlattenedCodeController,
# only: [:new],
# as: :verify_contract
# )
# end
resources(
"/verify-via-flattened-code",
AddressContractVerificationViaFlattenedCodeController,
only: [:new],
as: :verify_contract_via_flattened_code
)
resources(
"/verify-via-json",
AddressContractVerificationViaJsonController,
only: [:new],
as: :verify_contract_via_json
)
resources(
"/read-contract",
AddressReadContractController,

@ -87,7 +87,8 @@ msgid "A string with the name of the module to be invoked."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:156
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:156
msgid "ABI-encoded Constructor Arguments (if required by the contract)"
msgstr ""
@ -123,7 +124,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:16
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:26
#: lib/block_scout_web/views/address_view.ex:104
msgid "Address"
msgstr ""
@ -263,7 +264,9 @@ msgid "Call Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:415
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:88
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:305
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:50
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:47
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:54
msgid "Cancel"
@ -286,17 +289,20 @@ msgid "Clear"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:71
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:71
msgid "Compiler"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:37
#: lib/block_scout_web/templates/address_contract/index.html.eex:47
msgid "Compiler version"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:13
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:13
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:4
msgid "Connection Lost"
msgstr ""
@ -324,17 +330,19 @@ msgid "Connection Lost, click to load newer validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:56
#: lib/block_scout_web/templates/address_contract/index.html.eex:66
msgid "Constructor Arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:78
#: lib/block_scout_web/templates/address_contract/index.html.eex:104
msgid "Contract ABI"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:27
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:27
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:13
#: lib/block_scout_web/views/address_view.ex:102
msgid "Contract Address"
msgstr ""
@ -347,8 +355,8 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:109
#: lib/block_scout_web/templates/address_contract/index.html.eex:117
#: lib/block_scout_web/templates/address_contract/index.html.eex:135
#: lib/block_scout_web/templates/address_contract/index.html.eex:143
msgid "Contract Byte Code"
msgstr ""
@ -363,32 +371,34 @@ msgid "Contract Creation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:94
#: lib/block_scout_web/templates/address_contract/index.html.eex:120
msgid "Contract Creation Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:170
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:170
msgid "Contract Libraries"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:38
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:38
msgid "Contract Name"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:29
#: lib/block_scout_web/templates/address_contract/index.html.eex:39
msgid "Contract name:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:66
#: lib/block_scout_web/templates/address_contract/index.html.eex:76
msgid "Contract source code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:100
#: lib/block_scout_web/templates/address_contract/index.html.eex:126
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr ""
@ -398,7 +408,7 @@ msgid "Contribute"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:80
#: lib/block_scout_web/templates/address_contract/index.html.eex:106
msgid "Copy ABI"
msgstr ""
@ -411,7 +421,7 @@ msgid "Copy Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:96
#: lib/block_scout_web/templates/address_contract/index.html.eex:122
msgid "Copy Contract Creation Code"
msgstr ""
@ -421,7 +431,8 @@ msgid "Copy Decompiled Contract Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:68
#: lib/block_scout_web/templates/address_contract/index.html.eex:78
#: lib/block_scout_web/templates/address_contract/index.html.eex:92
msgid "Copy Source Code"
msgstr ""
@ -468,20 +479,20 @@ msgid "Curl"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:100
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:107
#: lib/block_scout_web/templates/log/_data_decoded_view.html.eex:7
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:103
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:110
msgid "Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:31
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:37
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:52
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:32
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:40
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:55
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:38
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:44
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:39
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:62
msgid "Decoded"
msgstr ""
@ -535,7 +546,7 @@ msgid "Details"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:101
#: lib/block_scout_web/templates/address_contract/index.html.eex:127
msgid "Displaying the init data provided of the creating transaction."
msgstr ""
@ -555,8 +566,8 @@ msgid "ERC-721 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:78
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:113
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:85
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:120
msgid "ETH"
msgstr ""
@ -566,8 +577,8 @@ msgid "ETH RPC API Documentation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:48
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:82
#: lib/block_scout_web/templates/address_contract/index.html.eex:58
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:82
msgid "EVM Version"
msgstr ""
@ -587,7 +598,8 @@ msgid "Emission Reward"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:124
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:124
msgid "Enter the Solidity Contract Code"
msgstr ""
@ -659,18 +671,18 @@ msgid "Nonce"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:151
#: lib/block_scout_web/templates/address_contract/index.html.eex:184
msgid "External libraries"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:32
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:39
msgid "Failed to decode input data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:34
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:35
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:41
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42
msgid "Failed to decode log data."
msgstr ""
@ -753,7 +765,7 @@ msgid "However, in general, the"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:25
msgid "IMPORTANT: This information is a best guess based on similar functions from other verified contracts."
msgstr ""
@ -911,7 +923,7 @@ msgid "Total Difficulty"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:18
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:25
#: lib/block_scout_web/views/transaction_view.ex:354
msgid "Transaction"
msgstr ""
@ -964,30 +976,22 @@ msgid "Less than"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:185
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:207
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:229
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:251
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:273
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:295
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:317
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:339
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:361
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:383
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:185
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:207
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:229
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:251
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:273
msgid "Library Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:175
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:197
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:219
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:241
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:263
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:285
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:307
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:329
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:351
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:373
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:175
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:197
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:219
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:241
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:263
msgid "Library Name"
msgstr ""
@ -1016,7 +1020,9 @@ msgid "Loading..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:409
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:69
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:299
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:44
msgid "Loading...."
msgstr ""
@ -1090,14 +1096,17 @@ msgid "Name"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:9
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:18
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:9
msgid "New Smart Contract Verification"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:55
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:98
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:141
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:55
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:98
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:141
#: lib/block_scout_web/templates/stakes/_rows.html.eex:24
msgid "No"
msgstr ""
@ -1109,13 +1118,13 @@ msgid "OUT"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:33
#: lib/block_scout_web/templates/address_contract/index.html.eex:43
msgid "Optimization enabled"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:42
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:114
#: lib/block_scout_web/templates/address_contract/index.html.eex:52
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:114
msgid "Optimization runs"
msgstr ""
@ -1166,7 +1175,7 @@ msgid "Pending Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:17
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:24
msgid "Potential matches from our contract method database:"
msgstr ""
@ -1184,7 +1193,7 @@ msgid "QR Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:82
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:89
msgid "Query"
msgstr ""
@ -1217,7 +1226,9 @@ msgid "Request URL"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:412
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:302
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:47
msgid "Reset"
msgstr ""
@ -1425,7 +1436,7 @@ msgid "This is useful to allow sending requests to blockscout without having to
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:19
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:26
msgid "To have guaranteed accuracy, use the link above to verify the contract's source code."
msgstr ""
@ -1442,8 +1453,8 @@ msgid "Topic"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:70
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:73
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:77
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:80
msgid "Topics"
msgstr ""
@ -1568,22 +1579,24 @@ msgid "Value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/address_contract/index.html.eex:125
#: lib/block_scout_web/templates/address_contract/index.html.eex:130
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:12
#: lib/block_scout_web/templates/address_contract/index.html.eex:22
#: lib/block_scout_web/templates/address_contract/index.html.eex:151
#: lib/block_scout_web/templates/address_contract/index.html.eex:163
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:19
msgid "Verify & Publish"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:411
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:301
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:46
msgid "Verify & publish"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:9
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:9
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:16
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:16
msgid "Verify the contract "
msgstr ""
@ -1635,7 +1648,7 @@ msgid "View transaction %{transaction} on %{subnetwork}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:112
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:119
msgid "WEI"
msgstr ""
@ -1650,9 +1663,10 @@ msgid "Wei"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:60
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:103
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:146
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:60
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:103
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:146
#: lib/block_scout_web/templates/stakes/_rows.html.eex:24
msgid "Yes"
msgstr ""
@ -1673,9 +1687,9 @@ msgid "false"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:9
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:9
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:16
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:16
msgid "here"
msgstr ""
@ -1761,7 +1775,7 @@ msgid "Loading chart"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:120
msgid "Log Index"
msgstr ""
@ -1924,7 +1938,7 @@ msgid "Waiting for transaction's confirmation..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:82
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:89
msgid "Write"
msgstr ""
@ -1950,22 +1964,22 @@ msgid "Search by address, token symbol, name, transaction hash, or block number"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:11
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:18
msgid "All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/address_contract/index.html.eex:22
msgid "All metadata displayed below is from that contract. In order to verify current contract, click"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/address_contract/index.html.eex:22
msgid "button"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:21
msgid "page"
msgstr ""
@ -1976,8 +1990,8 @@ msgid "Play"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:111
#: lib/block_scout_web/templates/address_contract/index.html.eex:121
#: lib/block_scout_web/templates/address_contract/index.html.eex:137
#: lib/block_scout_web/templates/address_contract/index.html.eex:147
msgid "Copy Byte Code"
msgstr ""
@ -2597,8 +2611,8 @@ msgid "Stakes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:18
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:9
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:16
msgid "Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB"
msgstr ""
@ -2754,3 +2768,36 @@ msgstr ""
#: lib/block_scout_web/templates/stakes/_stakes_modal_become_candidate.html.eex:16
msgid "Your Pool Short Description (optional)"
msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:26
msgid "Drop sources and metadata JSON file or click here"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:35
msgid "Flattened source code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:72
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:79
msgid "Next"
msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:23
msgid "Sources and Metadata JSON"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:40
msgid "Sources and metadata JSON file"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:31
msgid "This contract has been verified via Sourcify."
msgstr ""

@ -87,7 +87,8 @@ msgid "A string with the name of the module to be invoked."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:156
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:156
msgid "ABI-encoded Constructor Arguments (if required by the contract)"
msgstr ""
@ -123,7 +124,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:16
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:26
#: lib/block_scout_web/views/address_view.ex:104
msgid "Address"
msgstr ""
@ -263,7 +264,9 @@ msgid "Call Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:415
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:88
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:305
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:50
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:47
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:54
msgid "Cancel"
@ -286,17 +289,20 @@ msgid "Clear"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:71
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:71
msgid "Compiler"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:37
#: lib/block_scout_web/templates/address_contract/index.html.eex:47
msgid "Compiler version"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:13
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:13
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:4
msgid "Connection Lost"
msgstr ""
@ -324,17 +330,19 @@ msgid "Connection Lost, click to load newer validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:56
#: lib/block_scout_web/templates/address_contract/index.html.eex:66
msgid "Constructor Arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:78
#: lib/block_scout_web/templates/address_contract/index.html.eex:104
msgid "Contract ABI"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:27
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:27
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:13
#: lib/block_scout_web/views/address_view.ex:102
msgid "Contract Address"
msgstr ""
@ -347,8 +355,8 @@ msgid "Contract Address Pending"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:109
#: lib/block_scout_web/templates/address_contract/index.html.eex:117
#: lib/block_scout_web/templates/address_contract/index.html.eex:135
#: lib/block_scout_web/templates/address_contract/index.html.eex:143
msgid "Contract Byte Code"
msgstr ""
@ -363,32 +371,34 @@ msgid "Contract Creation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:94
#: lib/block_scout_web/templates/address_contract/index.html.eex:120
msgid "Contract Creation Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:170
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:170
msgid "Contract Libraries"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:38
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:38
msgid "Contract Name"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:29
#: lib/block_scout_web/templates/address_contract/index.html.eex:39
msgid "Contract name:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:66
#: lib/block_scout_web/templates/address_contract/index.html.eex:76
msgid "Contract source code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:100
#: lib/block_scout_web/templates/address_contract/index.html.eex:126
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr ""
@ -398,7 +408,7 @@ msgid "Contribute"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:80
#: lib/block_scout_web/templates/address_contract/index.html.eex:106
msgid "Copy ABI"
msgstr ""
@ -411,7 +421,7 @@ msgid "Copy Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:96
#: lib/block_scout_web/templates/address_contract/index.html.eex:122
msgid "Copy Contract Creation Code"
msgstr ""
@ -421,7 +431,8 @@ msgid "Copy Decompiled Contract Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:68
#: lib/block_scout_web/templates/address_contract/index.html.eex:78
#: lib/block_scout_web/templates/address_contract/index.html.eex:92
msgid "Copy Source Code"
msgstr ""
@ -468,20 +479,20 @@ msgid "Curl"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:100
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:107
#: lib/block_scout_web/templates/log/_data_decoded_view.html.eex:7
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:103
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:110
msgid "Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:31
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:37
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:52
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:32
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:40
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:55
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:38
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:44
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:39
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:62
msgid "Decoded"
msgstr ""
@ -535,7 +546,7 @@ msgid "Details"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:101
#: lib/block_scout_web/templates/address_contract/index.html.eex:127
msgid "Displaying the init data provided of the creating transaction."
msgstr ""
@ -555,8 +566,8 @@ msgid "ERC-721 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:78
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:113
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:85
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:120
msgid "ETH"
msgstr ""
@ -566,8 +577,8 @@ msgid "ETH RPC API Documentation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:48
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:82
#: lib/block_scout_web/templates/address_contract/index.html.eex:58
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:82
msgid "EVM Version"
msgstr ""
@ -587,7 +598,8 @@ msgid "Emission Reward"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:124
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:124
msgid "Enter the Solidity Contract Code"
msgstr ""
@ -659,18 +671,18 @@ msgid "Nonce"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:151
#: lib/block_scout_web/templates/address_contract/index.html.eex:184
msgid "External libraries"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:32
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:39
msgid "Failed to decode input data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:34
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:35
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:41
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42
msgid "Failed to decode log data."
msgstr ""
@ -753,7 +765,7 @@ msgid "However, in general, the"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:25
msgid "IMPORTANT: This information is a best guess based on similar functions from other verified contracts."
msgstr ""
@ -911,7 +923,7 @@ msgid "Total Difficulty"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:18
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:25
#: lib/block_scout_web/views/transaction_view.ex:354
msgid "Transaction"
msgstr ""
@ -964,30 +976,22 @@ msgid "Less than"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:185
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:207
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:229
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:251
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:273
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:295
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:317
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:339
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:361
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:383
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:185
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:207
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:229
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:251
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:273
msgid "Library Address"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:175
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:197
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:219
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:241
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:263
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:285
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:307
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:329
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:351
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:373
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:175
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:197
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:219
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:241
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:263
msgid "Library Name"
msgstr ""
@ -1016,7 +1020,9 @@ msgid "Loading..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:409
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:69
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:299
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:44
msgid "Loading...."
msgstr ""
@ -1090,14 +1096,17 @@ msgid "Name"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:9
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:18
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:9
msgid "New Smart Contract Verification"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:55
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:98
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:141
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:55
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:98
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:141
#: lib/block_scout_web/templates/stakes/_rows.html.eex:24
msgid "No"
msgstr ""
@ -1109,13 +1118,13 @@ msgid "OUT"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:33
#: lib/block_scout_web/templates/address_contract/index.html.eex:43
msgid "Optimization enabled"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:42
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:114
#: lib/block_scout_web/templates/address_contract/index.html.eex:52
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:114
msgid "Optimization runs"
msgstr ""
@ -1166,7 +1175,7 @@ msgid "Pending Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:17
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:24
msgid "Potential matches from our contract method database:"
msgstr ""
@ -1184,7 +1193,7 @@ msgid "QR Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:82
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:89
msgid "Query"
msgstr ""
@ -1217,7 +1226,9 @@ msgid "Request URL"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:412
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:302
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:47
msgid "Reset"
msgstr ""
@ -1425,7 +1436,7 @@ msgid "This is useful to allow sending requests to blockscout without having to
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:19
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:26
msgid "To have guaranteed accuracy, use the link above to verify the contract's source code."
msgstr ""
@ -1442,8 +1453,8 @@ msgid "Topic"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:70
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:73
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:77
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:80
msgid "Topics"
msgstr ""
@ -1568,22 +1579,24 @@ msgid "Value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/address_contract/index.html.eex:125
#: lib/block_scout_web/templates/address_contract/index.html.eex:130
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:12
#: lib/block_scout_web/templates/address_contract/index.html.eex:22
#: lib/block_scout_web/templates/address_contract/index.html.eex:151
#: lib/block_scout_web/templates/address_contract/index.html.eex:163
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:19
msgid "Verify & Publish"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:411
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:301
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:46
msgid "Verify & publish"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:9
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:9
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:16
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:16
msgid "Verify the contract "
msgstr ""
@ -1635,7 +1648,7 @@ msgid "View transaction %{transaction} on %{subnetwork}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:112
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:119
msgid "WEI"
msgstr ""
@ -1650,9 +1663,10 @@ msgid "Wei"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:60
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:103
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:146
#:
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:60
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:103
#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:146
#: lib/block_scout_web/templates/stakes/_rows.html.eex:24
msgid "Yes"
msgstr ""
@ -1673,9 +1687,9 @@ msgid "false"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:9
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:9
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:16
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:18
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:16
msgid "here"
msgstr ""
@ -1761,7 +1775,7 @@ msgid "Loading chart"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:120
msgid "Log Index"
msgstr ""
@ -1924,7 +1938,7 @@ msgid "Waiting for transaction's confirmation..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:82
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:89
msgid "Write"
msgstr ""
@ -1950,22 +1964,22 @@ msgid "Search by address, token symbol, name, transaction hash, or block number"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:11
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:18
msgid "All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/address_contract/index.html.eex:22
msgid "All metadata displayed below is from that contract. In order to verify current contract, click"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/address_contract/index.html.eex:22
msgid "button"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:21
msgid "page"
msgstr ""
@ -1976,8 +1990,8 @@ msgid "Play"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:111
#: lib/block_scout_web/templates/address_contract/index.html.eex:121
#: lib/block_scout_web/templates/address_contract/index.html.eex:137
#: lib/block_scout_web/templates/address_contract/index.html.eex:147
msgid "Copy Byte Code"
msgstr ""
@ -2597,8 +2611,8 @@ msgid "Stakes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:18
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:9
#: lib/block_scout_web/templates/address_contract/index.html.eex:20
#: lib/block_scout_web/templates/smart_contract/_functions.html.eex:16
msgid "Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB"
msgstr ""
@ -2754,3 +2768,36 @@ msgstr ""
#: lib/block_scout_web/templates/stakes/_stakes_modal_become_candidate.html.eex:16
msgid "Your Pool Short Description (optional)"
msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:26
msgid "Drop sources and metadata JSON file or click here"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:35
msgid "Flattened source code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:72
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:79
msgid "Next"
msgstr ""
#, elixir-format
#:
#: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:23
msgid "Sources and Metadata JSON"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:40
msgid "Sources and metadata JSON file"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:31
msgid "This contract has been verified via Sourcify."
msgstr ""

@ -6,7 +6,7 @@ defmodule BlockScoutWeb.ContractVerifyPage do
import Wallaby.Query
def visit_page(session, address_hash) do
visit(session, "/address/#{address_hash}/contract_verifications/new")
visit(session, "/address/#{address_hash}/verify-via-flattened-code/new")
end
def fill_form(session, %{

@ -241,6 +241,12 @@ config :explorer, Explorer.Chain.Cache.Uncles,
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.ThirdPartyIntegrations.Sourcify,
server_url: System.get_env("SOURCIFY_SERVER_URL") || "https://verification.komputing.org/server",
enabled: System.get_env("ENABLE_SOURCIFY_INTEGRATION") == "true",
chain_id: System.get_env("CHAIN_ID"),
repo_url: System.get_env("SOURCIFY_REPO_URL") || "https://contractrepo.komputing.org/contracts/full_match/"
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"

@ -53,6 +53,7 @@ defmodule Explorer.Chain do
Log,
PendingBlockOperation,
SmartContract,
SmartContractAdditionalSource,
StakingPool,
StakingPoolsDelegator,
Token,
@ -1315,7 +1316,12 @@ defmodule Explorer.Chain do
options \\ [],
query_decompiled_code_flag \\ false
) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
necessity_by_association =
options
|> Keyword.get(:necessity_by_association, %{})
|> Map.merge(%{
smart_contract_additional_sources: :optional
})
query =
from(
@ -3364,7 +3370,7 @@ defmodule Explorer.Chain do
naming the address for reference.
"""
@spec create_smart_contract(map()) :: {:ok, SmartContract.t()} | {:error, Ecto.Changeset.t()}
def create_smart_contract(attrs \\ %{}, external_libraries \\ []) do
def create_smart_contract(attrs \\ %{}, external_libraries \\ [], secondary_sources \\ []) do
new_contract = %SmartContract{}
smart_contract_changeset =
@ -3372,10 +3378,23 @@ defmodule Explorer.Chain do
|> SmartContract.changeset(attrs)
|> Changeset.put_change(:external_libraries, external_libraries)
new_contract_additional_source = %SmartContractAdditionalSource{}
smart_contract_additional_sources_changesets =
if secondary_sources do
secondary_sources
|> Enum.map(fn changeset ->
new_contract_additional_source
|> SmartContractAdditionalSource.changeset(changeset)
end)
else
[]
end
address_hash = Changeset.get_field(smart_contract_changeset, :address_hash)
# Enforce ShareLocks tables order (see docs: sharelocks.md)
insert_result =
insert_contract_query =
Multi.new()
|> Multi.run(:set_address_verified, fn repo, _ -> set_address_verified(repo, address_hash) end)
|> Multi.run(:clear_primary_address_names, fn repo, _ -> clear_primary_address_names(repo, address_hash) end)
@ -3384,6 +3403,16 @@ defmodule Explorer.Chain do
create_address_name(repo, name, address_hash)
end)
|> Multi.insert(:smart_contract, smart_contract_changeset)
insert_contract_query_with_additional_sources =
smart_contract_additional_sources_changesets
|> Enum.with_index()
|> Enum.reduce(insert_contract_query, fn {changeset, index}, multi ->
Multi.insert(multi, "smart_contract_additional_source_#{Integer.to_string(index)}", changeset)
end)
insert_result =
insert_contract_query_with_additional_sources
|> Repo.transaction()
case insert_result do
@ -3503,7 +3532,7 @@ defmodule Explorer.Chain do
def get_address_verified_twin_contract(address_hash) do
case Repo.get(Address, address_hash) do
nil ->
%{:verified_contract => nil}
%{:verified_contract => nil, :additional_sources => nil}
target_address ->
target_address_hash = target_address.hash
@ -3531,12 +3560,15 @@ defmodule Explorer.Chain do
verified_contract_twin_query
|> Repo.one(timeout: 10_000)
verified_contract_twin_additional_sources = get_contract_additional_sources(verified_contract_twin)
%{
:verified_contract => verified_contract_twin
:verified_contract => verified_contract_twin,
:additional_sources => verified_contract_twin_additional_sources
}
_ ->
%{:verified_contract => nil}
%{:verified_contract => nil, :additional_sources => nil}
end
end
end
@ -3587,6 +3619,21 @@ defmodule Explorer.Chain do
end
end
defp get_contract_additional_sources(verified_contract_twin) do
if verified_contract_twin do
verified_contract_twin_additional_sources_query =
from(
s in SmartContractAdditionalSource,
where: s.address_hash == ^verified_contract_twin.address_hash
)
verified_contract_twin_additional_sources_query
|> Repo.all()
else
[]
end
end
@spec address_hash_to_smart_contract(Hash.Address.t()) :: SmartContract.t() | nil
def address_hash_to_smart_contract(address_hash) do
query =
@ -3612,6 +3659,16 @@ defmodule Explorer.Chain do
end
end
def smart_contract_verified?(address_hash) do
query =
from(
smart_contract in SmartContract,
where: smart_contract.address_hash == ^address_hash
)
if Repo.one(query), do: true, else: false
end
defp fetch_transactions(paging_options \\ nil) do
Transaction
|> order_by([transaction], desc: transaction.block_number, desc: transaction.index)

@ -17,6 +17,7 @@ defmodule Explorer.Chain.Address do
Hash,
InternalTransaction,
SmartContract,
SmartContractAdditionalSource,
Token,
Transaction,
Wei
@ -110,6 +111,7 @@ defmodule Explorer.Chain.Address do
has_many(:names, Address.Name, foreign_key: :address_hash)
has_many(:decompiled_smart_contracts, DecompiledSmartContract, foreign_key: :address_hash)
has_many(:smart_contract_additional_sources, SmartContractAdditionalSource, foreign_key: :address_hash)
timestamps()
end

@ -192,6 +192,7 @@ defmodule Explorer.Chain.SmartContract do
produce `address` `t:Explorer.Chain.Address.t/0` `contract_code`.
* `abi` - The [JSON ABI specification](https://solidity.readthedocs.io/en/develop/abi-spec.html#json) for this
contract.
* `verified_via_sourcify` - whether contract verified through Sourcify utility or not.
"""
@type t :: %Explorer.Chain.SmartContract{
@ -202,7 +203,8 @@ defmodule Explorer.Chain.SmartContract do
constructor_arguments: String.t() | nil,
evm_version: String.t() | nil,
optimization_runs: non_neg_integer() | nil,
abi: [function_description]
abi: [function_description],
verified_via_sourcify: boolean | nil
}
schema "smart_contracts" do
@ -215,6 +217,7 @@ defmodule Explorer.Chain.SmartContract do
field(:optimization_runs, :integer)
embeds_many(:external_libraries, ExternalLibrary)
field(:abi, {:array, :map})
field(:verified_via_sourcify, :boolean)
has_many(
:decompiled_smart_contracts,
@ -248,7 +251,8 @@ defmodule Explorer.Chain.SmartContract do
:abi,
:constructor_arguments,
:evm_version,
:optimization_runs
:optimization_runs,
:verified_via_sourcify
])
|> validate_required([:name, :compiler_version, :optimization, :contract_source_code, :abi, :address_hash])
|> unique_constraint(:address_hash)
@ -266,7 +270,8 @@ defmodule Explorer.Chain.SmartContract do
:address_hash,
:evm_version,
:optimization_runs,
:constructor_arguments
:constructor_arguments,
:verified_via_sourcify
])
|> validate_required([:name, :compiler_version, :optimization, :address_hash])

@ -0,0 +1,63 @@
defmodule Explorer.Chain.SmartContractAdditionalSource do
@moduledoc """
The representation of a verified Smart Contract additional sources.
It is used when contract is verified with Sourcify utility.
"""
require Logger
use Explorer.Schema
alias Explorer.Chain.{Hash, SmartContract}
@typedoc """
* `file_name` - the name of the Solidity file with contract code (with extension).
* `contract_source_code` - the Solidity source code from the file with `file_name`.
"""
@type t :: %Explorer.Chain.SmartContractAdditionalSource{
file_name: String.t(),
contract_source_code: String.t()
}
schema "smart_contracts_additional_sources" do
field(:file_name, :string)
field(:contract_source_code, :string)
belongs_to(
:smart_contract,
SmartContract,
foreign_key: :address_hash,
references: :address_hash,
type: Hash.Address
)
timestamps()
end
def changeset(%__MODULE__{} = smart_contract_additional_source, attrs) do
smart_contract_additional_source
|> cast(attrs, [
:file_name,
:contract_source_code,
:address_hash
])
|> validate_required([:file_name, :contract_source_code, :address_hash])
|> unique_constraint(:address_hash)
end
def invalid_contract_changeset(%__MODULE__{} = smart_contract_additional_source, attrs, error) do
validated =
smart_contract_additional_source
|> cast(attrs, [
:file_name,
:contract_source_code,
:address_hash
])
|> validate_required([:file_name, :address_hash])
add_error(validated, :contract_source_code, error_message(error))
end
defp error_message(_), do: "There was an error validating your contract, please try again."
end

@ -45,10 +45,10 @@ defmodule Explorer.SmartContract.Publisher do
end
end
defp publish_smart_contract(address_hash, params, abi) do
def publish_smart_contract(address_hash, params, abi) do
attrs = address_hash |> attributes(params, abi)
Chain.create_smart_contract(attrs, attrs.external_libraries)
Chain.create_smart_contract(attrs, attrs.external_libraries, attrs.secondary_sources)
end
defp unverified_smart_contract(address_hash, params, error, error_message) do
@ -89,7 +89,9 @@ defmodule Explorer.SmartContract.Publisher do
contract_source_code: params["contract_source_code"],
constructor_arguments: clean_constructor_arguments,
external_libraries: prepared_external_libraries,
abi: abi
secondary_sources: params["secondary_sources"],
abi: abi,
verified_via_sourcify: params["verified_via_sourcify"]
}
end

@ -0,0 +1,184 @@
defmodule Explorer.ThirdPartyIntegrations.Sourcify do
@moduledoc """
Adapter for contracts verification with https://sourcify.dev/
"""
use Tesla
alias HTTPoison.{Error, Response}
alias Tesla.Multipart
def check_by_address(address_hash_string) do
chain_id = config(:chain_id)
params = [addresses: address_hash_string, chainIds: chain_id]
http_get_request(check_by_address_url(), params)
end
def get_metadata(address_hash_string) do
get_metadata_full_url = get_metadata_url() <> "/" <> address_hash_string
http_get_request(get_metadata_full_url, [])
end
def verify(address_hash_string, files) do
chain_id = config(:chain_id)
multipart_text_params =
Multipart.new()
|> Multipart.add_field("chain", chain_id)
|> Multipart.add_field("address", address_hash_string)
multipart_body =
files
|> Enum.reduce(multipart_text_params, fn file, acc ->
if file do
acc
|> Multipart.add_file(file.path,
name: "files",
file_name: Path.basename(file.path)
)
else
acc
end
end)
http_post_request(verify_url(), multipart_body)
end
def http_get_request(url, params) do
request = HTTPoison.get(url, [], params: params)
case request do
{:ok, %Response{body: body, status_code: 200}} ->
process_sourcify_response(url, body)
{:ok, %Response{body: body, status_code: status_code}} when status_code in 400..526 ->
parse_http_error_response(body)
{:ok, %Response{status_code: status_code}} when status_code in 300..308 ->
{:error, "Sourcify redirected"}
{:ok, %Response{status_code: _status_code}} ->
{:error, "Sourcify unexpected status code"}
{:error, %Error{reason: reason}} ->
{:error, reason}
{:error, :nxdomain} ->
{:error, "Sourcify is not responsive"}
{:error, _} ->
{:error, "Unexpected response from Sourcify"}
end
end
def http_post_request(url, body) do
request = Tesla.post(url, body)
case request do
{:ok, %Tesla.Env{body: body}} ->
process_sourcify_response(url, body)
_ ->
{:error, "Unexpected response from Sourcify verify method"}
end
end
defp process_sourcify_response(url, body) do
cond do
url =~ "checkByAddresses" ->
parse_check_by_address_http_response(body)
url =~ "/verify" ->
parse_verify_http_response(body)
url =~ "/files/" ->
parse_get_metadata_http_response(body)
true ->
{:error, body}
end
end
defp parse_verify_http_response(body) do
body_json = decode_json(body)
case body_json do
%{"result" => [%{"status" => "perfect"}]} ->
{:ok, body_json}
%{"result" => [%{"status" => unknown_status}]} ->
{:error, unknown_status}
body ->
{:error, body}
end
end
defp parse_check_by_address_http_response(body) do
body_json = decode_json(body)
case body_json do
[%{"status" => "perfect"}] ->
{:ok, body_json}
[%{"status" => "false"}] ->
{:error, "Contract is not verified"}
[%{"status" => unknown_status}] ->
{:error, unknown_status}
body ->
{:error, body}
end
end
defp parse_get_metadata_http_response(body) do
body_json = decode_json(body)
case body_json do
%{"message" => message, "errors" => errors} ->
{:error, "#{message}: #{decode_json(errors)}"}
metadata ->
{:ok, metadata}
end
end
defp parse_http_error_response(body) do
body_json = decode_json(body)
if is_map(body_json) do
{:error, body_json["error"]}
else
{:error, body}
end
end
def decode_json(data) do
Jason.decode!(data)
rescue
_ -> data
end
defp config(key) do
:explorer
|> Application.get_env(__MODULE__)
|> Keyword.get(key)
end
defp base_server_url do
config(:server_url)
end
defp verify_url do
"#{base_server_url()}" <> "/verify"
end
defp check_by_address_url do
"#{base_server_url()}" <> "/checkByAddresses"
end
defp get_metadata_url do
chain_id = config(:chain_id)
"#{base_server_url()}" <> "/files/" <> chain_id
end
end

@ -47,7 +47,8 @@ defmodule Explorer.Mixfile do
do: [
:logger,
:mix,
:runtime_tools
:runtime_tools,
:tesla
]
# Specifies your project dependencies.
@ -106,7 +107,8 @@ defmodule Explorer.Mixfile do
{:telemetry, "~> 0.4.1"},
# `Timex.Duration` for `Explorer.Counters.AverageBlockTime.average_block_time/0`
{:timex, "~> 3.6"},
{:con_cache, "~> 0.13"}
{:con_cache, "~> 0.13"},
{:tesla, "~> 1.3.3"}
]
end

@ -0,0 +1,22 @@
defmodule Explorer.Repo.Migrations.SupportSourcify do
use Ecto.Migration
def change do
alter table(:smart_contracts) do
add(:verified_via_sourcify, :boolean, null: true)
end
create table(:smart_contracts_additional_sources) do
add(:file_name, :string, null: false)
add(:contract_source_code, :text, null: false)
add(:address_hash, references(:smart_contracts, column: :address_hash, on_delete: :delete_all, type: :bytea),
null: false
)
timestamps()
end
create(index(:smart_contracts_additional_sources, :address_hash))
end
end

@ -3229,7 +3229,12 @@ defmodule Explorer.ChainTest do
test "finds a contract address" do
address =
insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil, names: [])
|> Repo.preload([:contracts_creation_internal_transaction, :contracts_creation_transaction, :token])
|> Repo.preload([
:contracts_creation_internal_transaction,
:contracts_creation_transaction,
:token,
:smart_contract_additional_sources
])
options = [
necessity_by_association: %{

@ -68,6 +68,7 @@ defmodule BlockScout.Mixfile do
defp deps do
[
{:absinthe_plug, git: "https://github.com/blockscout/absinthe_plug.git", tag: "1.5.3", override: true},
{:tesla, "~> 1.3.3"},
# Documentation
{:ex_doc, "~> 0.19.0", only: [:dev]},
{:number, "~> 1.0.3"}

Loading…
Cancel
Save