Merge branch 'master' into ab-fix-nested-constructor-arguments

pull/2326/head
Ayrat Badykov 5 years ago committed by GitHub
commit a239f84e74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .dialyzer-ignore
  2. 2
      CHANGELOG.md
  3. 2
      apps/block_scout_web/assets/js/app.js
  4. 28
      apps/block_scout_web/assets/js/lib/smart_contract/new_smart_contract_form.js
  5. 144
      apps/block_scout_web/assets/js/pages/verification_form.js
  6. 5
      apps/block_scout_web/config/config.exs
  7. 6
      apps/block_scout_web/config/dev.exs
  8. 14
      apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex
  9. 20
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_verification_controller.ex
  10. 36
      apps/block_scout_web/lib/block_scout_web/notifier.ex
  11. 1
      apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex
  12. 8
      apps/block_scout_web/lib/block_scout_web/router.ex
  13. 26
      apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
  14. 14
      apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification/new.html.eex
  15. 6
      apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
  16. 77
      apps/block_scout_web/priv/gettext/default.pot
  17. 83
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  18. 9
      apps/explorer/lib/explorer/chain.ex
  19. 2
      apps/explorer/lib/explorer/chain/events/publisher.ex
  20. 4
      apps/explorer/lib/explorer/chain/events/subscriber.ex
  21. 6
      apps/explorer/lib/explorer/chain/smart_contract.ex
  22. 12
      apps/explorer/lib/explorer/chain/smart_contract/external_library.ex
  23. 23
      apps/explorer/lib/explorer/smart_contract/publisher.ex
  24. 23
      apps/explorer/lib/explorer/smart_contract/publisher_worker.ex
  25. 1
      apps/explorer/mix.exs
  26. 13
      apps/explorer/priv/repo/migrations/20190709103104_add_external_libraries_to_smart_contracts.exs
  27. 3
      mix.lock

@ -5,3 +5,5 @@ apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex:400: Function timestamp_to_datetim
apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: Function microseconds_time/1 has no local return apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: Function microseconds_time/1 has no local return
apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: The call 'Elixir.System':convert_time_unit(__@1::any(),'native','microseconds') breaks the contract (integer(),time_unit() | 'native',time_unit() | 'native') -> integer() apps/explorer/lib/explorer/repo/prometheus_logger.ex:8: The call 'Elixir.System':convert_time_unit(__@1::any(),'native','microseconds') breaks the contract (integer(),time_unit() | 'native',time_unit() | 'native') -> integer()
apps/block_scout_web/lib/block_scout_web/views/layout_view.ex:174: The call 'Elixir.Poison.Parser':'parse!'(any(),#{'keys':='atoms!'}) will never return since the success typing is (binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),[{atom(),_}]) -> 'false' | 'nil' | 'true' | binary() | ['false' | 'nil' | 'true' | binary() | [any()] | number() | map()] | number() | map() and the contract is (iodata(),'Elixir.Keyword':t()) -> t() apps/block_scout_web/lib/block_scout_web/views/layout_view.ex:174: The call 'Elixir.Poison.Parser':'parse!'(any(),#{'keys':='atoms!'}) will never return since the success typing is (binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | []),[{atom(),_}]) -> 'false' | 'nil' | 'true' | binary() | ['false' | 'nil' | 'true' | binary() | [any()] | number() | map()] | number() | map() and the contract is (iodata(),'Elixir.Keyword':t()) -> t()
apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The pattern 'false' can never match the type 'true'
apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The test 5 == 'infinity' can never evaluate to 'true'

@ -19,6 +19,8 @@
- [#2289](https://github.com/poanetwork/blockscout/pull/2289) - Optional websockets for dev environment - [#2289](https://github.com/poanetwork/blockscout/pull/2289) - Optional websockets for dev environment
- [#2307](https://github.com/poanetwork/blockscout/pull/2307) - add GoJoy to README - [#2307](https://github.com/poanetwork/blockscout/pull/2307) - add GoJoy to README
- [#2293](https://github.com/poanetwork/blockscout/pull/2293) - remove request idle timeout configuration
## 2.0.1-beta ## 2.0.1-beta

@ -34,6 +34,7 @@ import './pages/transactions'
import './pages/favorites' import './pages/favorites'
import './pages/network-search' import './pages/network-search'
import './pages/layout' import './pages/layout'
import './pages/verification_form'
import './pages/admin/tasks.js' import './pages/admin/tasks.js'
@ -46,7 +47,6 @@ import './lib/market_history_chart'
import './lib/pending_transactions_toggle' import './lib/pending_transactions_toggle'
import './lib/pretty_json' import './lib/pretty_json'
import './lib/reload_button' import './lib/reload_button'
import './lib/smart_contract/new_smart_contract_form'
import './lib/smart_contract/read_only_functions' import './lib/smart_contract/read_only_functions'
import './lib/smart_contract/wei_ether_converter' import './lib/smart_contract/wei_ether_converter'
import './lib/stop_propagation' import './lib/stop_propagation'

@ -1,28 +0,0 @@
import $ from 'jquery'
$(function () {
$('.js-btn-add-contract-libraries').on('click', function () {
$('.js-smart-contract-libraries-wrapper').show()
$(this).hide()
})
$('.js-smart-contract-form-reset').on('click', function () {
$('.js-contract-library-form-group').removeClass('active')
$('.js-contract-library-form-group').first().addClass('active')
$('.js-smart-contract-libraries-wrapper').hide()
$('.js-btn-add-contract-libraries').show()
$('.js-add-contract-library-wrapper').show()
})
$('.js-btn-add-contract-library').on('click', function () {
let nextContractLibrary = $('.js-contract-library-form-group.active').next('.js-contract-library-form-group')
if (nextContractLibrary) {
nextContractLibrary.addClass('active')
}
if ($('.js-contract-library-form-group.active').length === $('.js-contract-library-form-group').length) {
$('.js-add-contract-library-wrapper').hide()
}
})
})

@ -0,0 +1,144 @@
import $ from 'jquery'
import _ from 'lodash'
import URI from 'urijs'
import humps from 'humps'
import { subscribeChannel } from '../socket'
import { createStore, connectElements } from '../lib/redux_helpers.js'
export const initialState = {
channelDisconnected: false,
addressHash: null,
newForm: null
}
export function reducer (state = initialState, action) {
switch (action.type) {
case 'PAGE_LOAD':
case 'ELEMENTS_LOAD': {
return Object.assign({}, state, _.omit(action, 'type'))
}
case 'CHANNEL_DISCONNECTED': {
if (state.beyondPageOne) return state
return Object.assign({}, state, {
channelDisconnected: true
})
}
case 'RECEIVED_VERIFICATION_RESULT': {
if (action.msg.verificationResult === 'ok') {
return window.location.replace(window.location.href.split('/contract_verifications')[0] + '/contracts')
} else {
return Object.assign({}, state, {
newForm: action.msg.verificationResult
})
}
}
default:
return state
}
}
const elements = {
'[data-selector="channel-disconnected-message"]': {
render ($el, state) {
if (state.channelDisconnected) $el.show()
}
},
'[data-page="contract-verification"]': {
render ($el, state) {
if (state.newForm) {
$el.replaceWith(state.newForm)
$('button[data-button-loading="animation"]').click(event => {
$('#loading').removeClass('d-none')
})
$(function () {
$('.js-btn-add-contract-libraries').on('click', function () {
$('.js-smart-contract-libraries-wrapper').show()
$(this).hide()
})
$('.js-smart-contract-form-reset').on('click', function () {
$('.js-contract-library-form-group').removeClass('active')
$('.js-contract-library-form-group').first().addClass('active')
$('.js-smart-contract-libraries-wrapper').hide()
$('.js-btn-add-contract-libraries').show()
$('.js-add-contract-library-wrapper').show()
})
$('.js-btn-add-contract-library').on('click', function () {
let nextContractLibrary = $('.js-contract-library-form-group.active').next('.js-contract-library-form-group')
if (nextContractLibrary) {
nextContractLibrary.addClass('active')
}
if ($('.js-contract-library-form-group.active').length === $('.js-contract-library-form-group').length) {
$('.js-add-contract-library-wrapper').hide()
}
})
})
return $el
}
return $el
}
}
}
const $contractVerificationPage = $('[data-page="contract-verification"]')
if ($contractVerificationPage.length) {
const store = createStore(reducer)
const addressHash = $('#smart_contract_address_hash').val()
const { filter, blockNumber } = humps.camelizeKeys(URI(window.location).query(true))
store.dispatch({
type: 'PAGE_LOAD',
addressHash,
filter,
beyondPageOne: !!blockNumber
})
connectElements({ store, elements })
const addressChannel = subscribeChannel(`addresses:${addressHash}`)
addressChannel.onError(() => store.dispatch({
type: 'CHANNEL_DISCONNECTED'
}))
addressChannel.on('verification', (msg) => store.dispatch({
type: 'RECEIVED_VERIFICATION_RESULT',
msg: humps.camelizeKeys(msg)
}))
$('button[data-button-loading="animation"]').click(event => {
$('#loading').removeClass('d-none')
})
$(function () {
$('.js-btn-add-contract-libraries').on('click', function () {
$('.js-smart-contract-libraries-wrapper').show()
$(this).hide()
})
$('.js-smart-contract-form-reset').on('click', function () {
$('.js-contract-library-form-group').removeClass('active')
$('.js-contract-library-form-group').first().addClass('active')
$('.js-smart-contract-libraries-wrapper').hide()
$('.js-btn-add-contract-libraries').show()
$('.js-add-contract-library-wrapper').show()
})
$('.js-btn-add-contract-library').on('click', function () {
let nextContractLibrary = $('.js-contract-library-form-group.active').next('.js-contract-library-form-group')
if (nextContractLibrary) {
nextContractLibrary.addClass('active')
}
if ($('.js-contract-library-form-group.active').length === $('.js-contract-library-form-group').length) {
$('.js-add-contract-library-wrapper').hide()
}
})
})
}

@ -35,11 +35,6 @@ config :block_scout_web, BlockScoutWeb.Counters.BlocksIndexedCounter, enabled: t
# Configures the endpoint # Configures the endpoint
config :block_scout_web, BlockScoutWeb.Endpoint, config :block_scout_web, BlockScoutWeb.Endpoint,
instrumenters: [BlockScoutWeb.Prometheus.Instrumenter, SpandexPhoenix.Instrumenter], instrumenters: [BlockScoutWeb.Prometheus.Instrumenter, SpandexPhoenix.Instrumenter],
http: [
protocol_options: [
idle_timeout: 90_000
]
],
url: [ url: [
host: System.get_env("BLOCKSCOUT_HOST") || "localhost", host: System.get_env("BLOCKSCOUT_HOST") || "localhost",
path: System.get_env("NETWORK_PATH") || "/" path: System.get_env("NETWORK_PATH") || "/"

@ -16,15 +16,9 @@ port =
config :block_scout_web, BlockScoutWeb.Endpoint, config :block_scout_web, BlockScoutWeb.Endpoint,
http: [ http: [
protocol_options: [
idle_timeout: 90_000
],
port: port || 4000 port: port || 4000
], ],
https: [ https: [
protocol_options: [
idle_timeout: 90_000
],
port: (port && port + 1) || 4001, port: (port && port + 1) || 4001,
cipher_suite: :strong, cipher_suite: :strong,
certfile: System.get_env("CERTFILE") || "priv/cert/selfsigned.pem", certfile: System.get_env("CERTFILE") || "priv/cert/selfsigned.pem",

@ -11,7 +11,7 @@ defmodule BlockScoutWeb.AddressChannel do
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Phoenix.View alias Phoenix.View
intercept(["balance_update", "coin_balance", "count", "internal_transaction", "transaction"]) intercept(["balance_update", "coin_balance", "count", "internal_transaction", "transaction", "verification_result"])
def join("addresses:" <> address_hash, _params, socket) do def join("addresses:" <> address_hash, _params, socket) do
{:ok, %{}, assign(socket, :address_hash, address_hash)} {:ok, %{}, assign(socket, :address_hash, address_hash)}
@ -58,6 +58,18 @@ defmodule BlockScoutWeb.AddressChannel do
end end
end end
def handle_out("verification_result", result, socket) do
case result[:result] do
{:ok, _contract} ->
push(socket, "verification", %{verification_result: :ok})
{:noreply, socket}
{:error, result} ->
push(socket, "verification", %{verification_result: result})
{:noreply, socket}
end
end
def handle_out("count", %{count: count}, socket) do def handle_out("count", %{count: count}, socket) do
Gettext.put_locale(BlockScoutWeb.Gettext, socket.assigns.locale) Gettext.put_locale(BlockScoutWeb.Gettext, socket.assigns.locale)

@ -2,7 +2,7 @@ defmodule BlockScoutWeb.AddressContractVerificationController do
use BlockScoutWeb, :controller use BlockScoutWeb, :controller
alias Explorer.Chain.SmartContract alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.{Publisher, Solidity.CodeCompiler, Solidity.CompilerVersion} alias Explorer.SmartContract.{PublisherWorker, Solidity.CodeCompiler, Solidity.CompilerVersion}
def new(conn, %{"address_id" => address_hash_string}) do def new(conn, %{"address_id" => address_hash_string}) do
changeset = changeset =
@ -16,31 +16,21 @@ defmodule BlockScoutWeb.AddressContractVerificationController do
render(conn, "new.html", render(conn, "new.html",
changeset: changeset, changeset: changeset,
compiler_versions: compiler_versions, compiler_versions: compiler_versions,
evm_versions: CodeCompiler.allowed_evm_versions() evm_versions: CodeCompiler.allowed_evm_versions(),
address_hash: address_hash_string
) )
end end
def create( def create(
conn, conn,
%{ %{
"address_id" => address_hash_string,
"smart_contract" => smart_contract, "smart_contract" => smart_contract,
"external_libraries" => external_libraries "external_libraries" => external_libraries
} }
) do ) do
case Publisher.publish(address_hash_string, smart_contract, external_libraries) do Que.add(PublisherWorker, {smart_contract["address_hash"], smart_contract, external_libraries, conn})
{:ok, _smart_contract} ->
redirect(conn, to: address_contract_path(conn, :index, address_hash_string))
{:error, changeset} -> send_resp(conn, 204, "")
{:ok, compiler_versions} = CompilerVersion.fetch_versions()
render(conn, "new.html",
changeset: changeset,
compiler_versions: compiler_versions,
evm_versions: CodeCompiler.allowed_evm_versions()
)
end
end end
def parse_optimization_runs(%{"runs" => runs}) do def parse_optimization_runs(%{"runs" => runs}) do

@ -4,11 +4,13 @@ defmodule BlockScoutWeb.Notifier do
""" """
alias Absinthe.Subscription alias Absinthe.Subscription
alias BlockScoutWeb.Endpoint alias BlockScoutWeb.{AddressContractVerificationView, Endpoint}
alias Explorer.{Chain, Market, Repo} alias Explorer.{Chain, Market, Repo}
alias Explorer.Chain.{Address, InternalTransaction, Transaction} alias Explorer.Chain.{Address, InternalTransaction, Transaction}
alias Explorer.Counters.AverageBlockTime alias Explorer.Counters.AverageBlockTime
alias Explorer.ExchangeRates.Token alias Explorer.ExchangeRates.Token
alias Explorer.SmartContract.{Solidity.CodeCompiler, Solidity.CompilerVersion}
alias Phoenix.View
def handle_event({:chain_event, :addresses, type, addresses}) when type in [:realtime, :on_demand] do def handle_event({:chain_event, :addresses, type, addresses}) when type in [:realtime, :on_demand] do
Endpoint.broadcast("addresses:new_address", "count", %{count: Chain.count_addresses_with_balance_from_cache()}) Endpoint.broadcast("addresses:new_address", "count", %{count: Chain.count_addresses_with_balance_from_cache()})
@ -23,6 +25,38 @@ defmodule BlockScoutWeb.Notifier do
Enum.each(address_coin_balances, &broadcast_address_coin_balance/1) Enum.each(address_coin_balances, &broadcast_address_coin_balance/1)
end end
def handle_event(
{:chain_event, :contract_verification_result, :on_demand, {address_hash, contract_verification_result, conn}}
) do
contract_verification_result =
case contract_verification_result do
{:ok, _} = result ->
result
{:error, changeset} ->
{:ok, compiler_versions} = CompilerVersion.fetch_versions()
result =
View.render_to_string(AddressContractVerificationView, "new.html",
changeset: changeset,
compiler_versions: compiler_versions,
evm_versions: CodeCompiler.allowed_evm_versions(),
address_hash: address_hash,
conn: conn
)
{:error, result}
end
Endpoint.broadcast(
"addresses:#{address_hash}",
"verification_result",
%{
result: contract_verification_result
}
)
end
def handle_event({:chain_event, :block_rewards, :realtime, rewards}) do def handle_event({:chain_event, :block_rewards, :realtime, rewards}) do
if Application.get_env(:block_scout_web, BlockScoutWeb.Chain)[:has_emission_funds] do if Application.get_env(:block_scout_web, BlockScoutWeb.Chain)[:has_emission_funds] do
broadcast_rewards(rewards) broadcast_rewards(rewards)

@ -23,6 +23,7 @@ defmodule BlockScoutWeb.RealtimeEventHandler do
Subscriber.to(:transactions, :realtime) Subscriber.to(:transactions, :realtime)
Subscriber.to(:addresses, :on_demand) Subscriber.to(:addresses, :on_demand)
Subscriber.to(:address_coin_balances, :on_demand) Subscriber.to(:address_coin_balances, :on_demand)
Subscriber.to(:contract_verification_result, :on_demand)
# Does not come from the indexer # Does not come from the indexer
Subscriber.to(:exchange_rate) Subscriber.to(:exchange_rate)
{:ok, []} {:ok, []}

@ -29,6 +29,12 @@ defmodule BlockScoutWeb.Router do
resources("/verified_smart_contracts", VerifiedSmartContractController, only: [:create]) resources("/verified_smart_contracts", VerifiedSmartContractController, only: [:create])
end end
scope "/verify_smart_contract" do
pipe_through(:api)
post("/contract_verifications", BlockScoutWeb.AddressContractVerificationController, :create)
end
scope "/api", BlockScoutWeb.API.RPC do scope "/api", BlockScoutWeb.API.RPC do
pipe_through(:api) pipe_through(:api)
@ -161,7 +167,7 @@ defmodule BlockScoutWeb.Router do
resources( resources(
"/contract_verifications", "/contract_verifications",
AddressContractVerificationController, AddressContractVerificationController,
only: [:new, :create], only: [:new],
as: :verify_contract as: :verify_contract
) )

@ -52,17 +52,6 @@
<dd class="col-sm-8 col-md-10"><%= @address.smart_contract.constructor_arguments %></dd> <dd class="col-sm-8 col-md-10"><%= @address.smart_contract.constructor_arguments %></dd>
</dl> </dl>
<% end %> <% end %>
<%= if @address.smart_contract.external_libraries do %>
<section>
<div class="d-flex justify-content-between align-items-baseline">
<h3><%= gettext "External libraries" %></h3>
</div>
<div class="tile tile-muted mb-4">
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= format_smart_contract_abi(@address.smart_contract.abi) %></code>
</pre>
</div>
</section>
<% end %>
</div> </div>
<hr/> <hr/>
<section> <section>
@ -109,7 +98,7 @@
</div> </div>
<% {:ok, contract_code} -> %> <% {:ok, contract_code} -> %>
<div class="d-flex justify-content-between align-items-baseline"> <div class="d-flex justify-content-between align-items-baseline">
<h2 class="card-title"><%= gettext "Contract Byte Code" %></h2> <h3><%= gettext "Contract Byte Code" %></h3>
<button type="button" class="btn-line" id="button" data-clipboard-text="<%= contract_code %>" aria-label="copy contract creation code"> <button type="button" class="btn-line" id="button" data-clipboard-text="<%= contract_code %>" aria-label="copy contract creation code">
<%= gettext "Copy Contract Byte Code" %> <%= gettext "Copy Contract Byte Code" %>
</button> </button>
@ -120,6 +109,19 @@
<% end %> <% end %>
</section> </section>
<%= if BlockScoutWeb.AddressView.smart_contract_verified?(@address) do %>
<%= if @address.smart_contract.external_libraries && @address.smart_contract.external_libraries != [] do %>
<section>
<div class="d-flex justify-content-between align-items-baseline">
<h3><%= gettext "External libraries" %></h3>
</div>
<div class="tile tile-muted mb-4">
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= format_external_libraries(@address.smart_contract.external_libraries) %></code>
</pre>
</div>
</section>
<% end %>
<% end %>
</div> </div>
</div> </div>
</section> </section>

@ -1,9 +1,15 @@
<section class="container new-smart-contract-container"> <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"> <div class="new-smart-contract-form">
<h1 class="smart-contract-title"><%= gettext "New Smart Contract Verification" %></h1> <h1 class="smart-contract-title"><%= gettext "New Smart Contract Verification" %></h1>
<%= form_for @changeset, <%= form_for @changeset,
address_verify_contract_path(@conn, :create, @conn.params["address_id"]), address_contract_verification_path(@conn, :create),
[], [],
fn f -> %> fn f -> %>
@ -240,13 +246,13 @@
</span> </span>
<%= gettext("Loading....") %> <%= gettext("Loading....") %>
</button> </button>
<%= submit gettext("Verify & publish"), class: "btn-full-primary mr-2", "data-loading": "animation" %> <%= 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" %> <%= reset gettext("Reset"), class: "btn-line mr-2 js-smart-contract-form-reset" %>
<%= <%=
link( link(
gettext("Cancel"), gettext("Cancel"),
class: "btn-no-border", class: "btn-no-border",
to: address_contract_path(@conn, :index, @conn.params["address_id"]) to: address_contract_path(@conn, :index, @address_hash)
) )
%> %>
</div> </div>

@ -21,6 +21,12 @@ defmodule BlockScoutWeb.AddressContractView do
def format_optimization_text(true), do: gettext("true") def format_optimization_text(true), do: gettext("true")
def format_optimization_text(false), do: gettext("false") def format_optimization_text(false), do: gettext("false")
def format_external_libraries(libraries) do
Enum.reduce(libraries, "", fn %{name: name, address_hash: address_hash}, acc ->
acc <> name <> " : " <> address_hash <> "\n"
end)
end
def contract_lines_with_index(contract_source_code) do def contract_lines_with_index(contract_source_code) do
contract_lines = String.split(contract_source_code, "\n") contract_lines = String.split(contract_source_code, "\n")

@ -197,7 +197,7 @@ msgid "Blocks Validated"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:247 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:253
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:47 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:47
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
@ -225,7 +225,7 @@ msgid "Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:34 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:40
msgid "Compiler" msgid "Compiler"
msgstr "" msgstr ""
@ -258,12 +258,12 @@ msgid "Connection Lost, click to load newer validations"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:82 #: lib/block_scout_web/templates/address_contract/index.html.eex:71
msgid "Contract ABI" msgid "Contract ABI"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:12 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/views/address_view.ex:97 #: lib/block_scout_web/views/address_view.ex:97
msgid "Contract Address" msgid "Contract Address"
msgstr "" msgstr ""
@ -286,7 +286,7 @@ msgid "Contract Creation"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:23 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:29
msgid "Contract Name" msgid "Contract Name"
msgstr "" msgstr ""
@ -296,7 +296,7 @@ msgid "Contract name:"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:70 #: lib/block_scout_web/templates/address_contract/index.html.eex:59
msgid "Contract source code" msgid "Contract source code"
msgstr "" msgstr ""
@ -560,7 +560,7 @@ msgid "Name"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:61 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:67
msgid "No" msgid "No"
msgstr "" msgstr ""
@ -651,7 +651,7 @@ msgid "Request URL"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:244 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:250
msgid "Reset" msgid "Reset"
msgstr "" msgstr ""
@ -939,7 +939,7 @@ msgid "Verify & Publish"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:243 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:249
msgid "Verify & publish" msgid "Verify & publish"
msgstr "" msgstr ""
@ -989,7 +989,7 @@ msgid "Wei"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:66 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:72
msgid "Yes" msgid "Yes"
msgstr "" msgstr ""
@ -1062,7 +1062,7 @@ msgid "Loading..."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:241 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:247
msgid "Loading...." msgid "Loading...."
msgstr "" msgstr ""
@ -1405,17 +1405,17 @@ msgid "Support"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:84 #: lib/block_scout_web/templates/address_contract/index.html.eex:73
msgid "Copy ABI" msgid "Copy ABI"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:100 #: lib/block_scout_web/templates/address_contract/index.html.eex:89
msgid "Copy Contract Creation Code" msgid "Copy Contract Creation Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:72 #: lib/block_scout_web/templates/address_contract/index.html.eex:61
msgid "Copy Source Code" msgid "Copy Source Code"
msgstr "" msgstr ""
@ -1425,7 +1425,7 @@ msgid "Genesis Block"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:112 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:118
msgid "Contract Libraries" msgid "Contract Libraries"
msgstr "" msgstr ""
@ -1488,7 +1488,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:35 #: lib/block_scout_web/templates/address_contract/index.html.eex:35
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:45 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:51
msgid "EVM Version" msgid "EVM Version"
msgstr "" msgstr ""
@ -1519,7 +1519,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:45 #: lib/block_scout_web/templates/address_contract/index.html.eex:45
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:77 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:83
msgid "Optimization runs" msgid "Optimization runs"
msgstr "" msgstr ""
@ -1585,27 +1585,27 @@ msgid "Block Details"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:112 #: lib/block_scout_web/templates/address_contract/index.html.eex:101
msgid "Contract Byte Code" msgid "Contract Byte Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:98 #: lib/block_scout_web/templates/address_contract/index.html.eex:87
msgid "Contract Creation Code" msgid "Contract Creation Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:104 #: lib/block_scout_web/templates/address_contract/index.html.eex:93
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:114 #: lib/block_scout_web/templates/address_contract/index.html.eex:103
msgid "Copy Contract Byte Code" msgid "Copy Contract Byte Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:105 #: lib/block_scout_web/templates/address_contract/index.html.eex:94
msgid "Displaying the init data provided of the creating transaction." msgid "Displaying the init data provided of the creating transaction."
msgstr "" msgstr ""
@ -1655,35 +1655,35 @@ msgid "Topic"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:98 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:104
msgid "ABI-encoded Constructor Arguments (if required by the contract)" msgid "ABI-encoded Constructor Arguments (if required by the contract)"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:87 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:93
msgid "Enter the Solidity Contract Code" msgid "Enter the Solidity Contract Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:127 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:133
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:149 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:155
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:171 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:177
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:193 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:199
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:215 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:221
msgid "Library Address" msgid "Library Address"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:117 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:123
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:139 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:145
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:161 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:167
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:183 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:189
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:205 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:211
msgid "Library Name" msgid "Library Name"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:3 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:9
msgid "New Smart Contract Verification" msgid "New Smart Contract Verification"
msgstr "" msgstr ""
@ -1769,7 +1769,7 @@ msgid "ERC-721 "
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:58 #: lib/block_scout_web/templates/address_contract/index.html.eex:116
msgid "External libraries" msgid "External libraries"
msgstr "" msgstr ""
@ -1797,3 +1797,8 @@ msgstr ""
#: lib/block_scout_web/templates/layout/_network_selector.html.eex:12 #: lib/block_scout_web/templates/layout/_network_selector.html.eex:12
msgid "Use the search box to find a hosted network, or select from the list of available networks below." msgid "Use the search box to find a hosted network, or select from the list of available networks below."
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4
msgid "Connection Lost"
msgstr ""

@ -197,7 +197,7 @@ msgid "Blocks Validated"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:247 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:253
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:47 #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:47
msgid "Cancel" msgid "Cancel"
msgstr "" msgstr ""
@ -225,7 +225,7 @@ msgid "Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:34 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:40
msgid "Compiler" msgid "Compiler"
msgstr "" msgstr ""
@ -258,12 +258,12 @@ msgid "Connection Lost, click to load newer validations"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:82 #: lib/block_scout_web/templates/address_contract/index.html.eex:71
msgid "Contract ABI" msgid "Contract ABI"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:12 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:18
#: lib/block_scout_web/views/address_view.ex:97 #: lib/block_scout_web/views/address_view.ex:97
msgid "Contract Address" msgid "Contract Address"
msgstr "" msgstr ""
@ -286,7 +286,7 @@ msgid "Contract Creation"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:23 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:29
msgid "Contract Name" msgid "Contract Name"
msgstr "" msgstr ""
@ -296,7 +296,7 @@ msgid "Contract name:"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:70 #: lib/block_scout_web/templates/address_contract/index.html.eex:59
msgid "Contract source code" msgid "Contract source code"
msgstr "" msgstr ""
@ -560,7 +560,7 @@ msgid "Name"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:61 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:67
msgid "No" msgid "No"
msgstr "" msgstr ""
@ -651,7 +651,7 @@ msgid "Request URL"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:244 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:250
msgid "Reset" msgid "Reset"
msgstr "" msgstr ""
@ -674,7 +674,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: #:
#: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:28 #: lib/block_scout_web/templates/address_token_balance/_token_balances.html.eex:30
msgid "Search tokens" msgid "Search tokens"
msgstr "" msgstr ""
@ -877,7 +877,7 @@ msgid "Transactions"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tile.html.eex:19 #: lib/block_scout_web/templates/address/_tile.html.eex:31
msgid "Transactions sent" msgid "Transactions sent"
msgstr "" msgstr ""
@ -923,7 +923,7 @@ msgid "Validated Transactions"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address/_tile.html.eex:23 #: lib/block_scout_web/templates/address/_tile.html.eex:35
msgid "Validations" msgid "Validations"
msgstr "" msgstr ""
@ -939,7 +939,7 @@ msgid "Verify & Publish"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:243 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:249
msgid "Verify & publish" msgid "Verify & publish"
msgstr "" msgstr ""
@ -989,7 +989,7 @@ msgid "Wei"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:66 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:72
msgid "Yes" msgid "Yes"
msgstr "" msgstr ""
@ -1062,7 +1062,7 @@ msgid "Loading..."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:241 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:247
msgid "Loading...." msgid "Loading...."
msgstr "" msgstr ""
@ -1405,17 +1405,17 @@ msgid "Support"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:84 #: lib/block_scout_web/templates/address_contract/index.html.eex:73
msgid "Copy ABI" msgid "Copy ABI"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:100 #: lib/block_scout_web/templates/address_contract/index.html.eex:89
msgid "Copy Contract Creation Code" msgid "Copy Contract Creation Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:72 #: lib/block_scout_web/templates/address_contract/index.html.eex:61
msgid "Copy Source Code" msgid "Copy Source Code"
msgstr "" msgstr ""
@ -1425,7 +1425,7 @@ msgid "Genesis Block"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:112 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:118
msgid "Contract Libraries" msgid "Contract Libraries"
msgstr "" msgstr ""
@ -1488,7 +1488,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:35 #: lib/block_scout_web/templates/address_contract/index.html.eex:35
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:45 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:51
msgid "EVM Version" msgid "EVM Version"
msgstr "" msgstr ""
@ -1519,7 +1519,7 @@ msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:45 #: lib/block_scout_web/templates/address_contract/index.html.eex:45
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:77 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:83
msgid "Optimization runs" msgid "Optimization runs"
msgstr "" msgstr ""
@ -1585,27 +1585,27 @@ msgid "Block Details"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:112 #: lib/block_scout_web/templates/address_contract/index.html.eex:101
msgid "Contract Byte Code" msgid "Contract Byte Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:98 #: lib/block_scout_web/templates/address_contract/index.html.eex:87
msgid "Contract Creation Code" msgid "Contract Creation Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:104 #: lib/block_scout_web/templates/address_contract/index.html.eex:93
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:114 #: lib/block_scout_web/templates/address_contract/index.html.eex:103
msgid "Copy Contract Byte Code" msgid "Copy Contract Byte Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:105 #: lib/block_scout_web/templates/address_contract/index.html.eex:94
msgid "Displaying the init data provided of the creating transaction." msgid "Displaying the init data provided of the creating transaction."
msgstr "" msgstr ""
@ -1655,35 +1655,35 @@ msgid "Topic"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:98 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:104
msgid "ABI-encoded Constructor Arguments (if required by the contract)" msgid "ABI-encoded Constructor Arguments (if required by the contract)"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:87 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:93
msgid "Enter the Solidity Contract Code" msgid "Enter the Solidity Contract Code"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:127 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:133
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:149 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:155
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:171 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:177
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:193 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:199
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:215 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:221
msgid "Library Address" msgid "Library Address"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:117 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:123
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:139 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:145
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:161 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:167
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:183 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:189
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:205 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:211
msgid "Library Name" msgid "Library Name"
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:3 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:9
msgid "New Smart Contract Verification" msgid "New Smart Contract Verification"
msgstr "" msgstr ""
@ -1769,7 +1769,7 @@ msgid "ERC-721 "
msgstr "" msgstr ""
#, elixir-format #, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:58 #: lib/block_scout_web/templates/address_contract/index.html.eex:116
msgid "External libraries" msgid "External libraries"
msgstr "" msgstr ""
@ -1797,3 +1797,8 @@ msgstr ""
#: lib/block_scout_web/templates/layout/_network_selector.html.eex:12 #: lib/block_scout_web/templates/layout/_network_selector.html.eex:12
msgid "Use the search box to find a hosted network, or select from the list of available networks below." msgid "Use the search box to find a hosted network, or select from the list of available networks below."
msgstr "" msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4
msgid "Connection Lost"
msgstr ""

@ -2426,8 +2426,13 @@ defmodule Explorer.Chain do
naming the address for reference. naming the address for reference.
""" """
@spec create_smart_contract(map()) :: {:ok, SmartContract.t()} | {:error, Ecto.Changeset.t()} @spec create_smart_contract(map()) :: {:ok, SmartContract.t()} | {:error, Ecto.Changeset.t()}
def create_smart_contract(attrs \\ %{}) do def create_smart_contract(attrs \\ %{}, external_libraries \\ []) do
smart_contract_changeset = SmartContract.changeset(%SmartContract{}, attrs) new_contract = %SmartContract{}
smart_contract_changeset =
new_contract
|> SmartContract.changeset(attrs)
|> Changeset.put_change(:external_libraries, external_libraries)
insert_result = insert_result =
Multi.new() Multi.new()

@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Publisher do
Publishes events related to the Chain context. Publishes events related to the Chain context.
""" """
@allowed_events ~w(addresses address_coin_balances blocks block_rewards internal_transactions token_transfers transactions)a @allowed_events ~w(addresses address_coin_balances blocks block_rewards internal_transactions token_transfers transactions contract_verification_result)a
def broadcast(_data, false), do: :ok def broadcast(_data, false), do: :ok

@ -3,9 +3,9 @@ defmodule Explorer.Chain.Events.Subscriber do
Subscribes to events related to the Chain context. Subscribes to events related to the Chain context.
""" """
@allowed_broadcast_events ~w(addresses address_coin_balances blocks block_rewards internal_transactions token_transfers transactions)a @allowed_broadcast_events ~w(addresses address_coin_balances blocks block_rewards internal_transactions token_transfers transactions contract_verification_result)a
@allowed_broadcast_types ~w(catchup realtime on_demand)a @allowed_broadcast_types ~w(catchup realtime on_demand contract_verification_result)a
@allowed_events ~w(exchange_rate)a @allowed_events ~w(exchange_rate)a

@ -13,6 +13,7 @@ defmodule Explorer.Chain.SmartContract do
use Explorer.Schema use Explorer.Schema
alias Explorer.Chain.{Address, ContractMethod, DecompiledSmartContract, Hash} alias Explorer.Chain.{Address, ContractMethod, DecompiledSmartContract, Hash}
alias Explorer.Chain.SmartContract.ExternalLibrary
alias Explorer.Repo alias Explorer.Repo
@typedoc """ @typedoc """
@ -212,7 +213,7 @@ defmodule Explorer.Chain.SmartContract do
field(:constructor_arguments, :string) field(:constructor_arguments, :string)
field(:evm_version, :string) field(:evm_version, :string)
field(:optimization_runs, :integer) field(:optimization_runs, :integer)
field(:external_libraries, :map) embeds_many(:external_libraries, ExternalLibrary)
field(:abi, {:array, :map}) field(:abi, {:array, :map})
has_many( has_many(
@ -247,8 +248,7 @@ defmodule Explorer.Chain.SmartContract do
:abi, :abi,
:constructor_arguments, :constructor_arguments,
:evm_version, :evm_version,
:optimization_runs, :optimization_runs
:external_libraries
]) ])
|> validate_required([:name, :compiler_version, :optimization, :contract_source_code, :abi, :address_hash]) |> validate_required([:name, :compiler_version, :optimization, :contract_source_code, :abi, :address_hash])
|> unique_constraint(:address_hash) |> unique_constraint(:address_hash)

@ -0,0 +1,12 @@
defmodule Explorer.Chain.SmartContract.ExternalLibrary do
@moduledoc """
The representation of an external library that was used for a smart contract.
"""
use Ecto.Schema
embedded_schema do
field(:name)
field(:address_hash)
end
end

@ -28,17 +28,17 @@ defmodule Explorer.SmartContract.Publisher do
case Verifier.evaluate_authenticity(address_hash, params_with_external_libaries) do case Verifier.evaluate_authenticity(address_hash, params_with_external_libaries) do
{:ok, %{abi: abi}} -> {:ok, %{abi: abi}} ->
publish_smart_contract(address_hash, params, abi) publish_smart_contract(address_hash, params_with_external_libaries, abi)
{:error, error} -> {:error, error} ->
{:error, unverified_smart_contract(address_hash, params, error)} {:error, unverified_smart_contract(address_hash, params_with_external_libaries, error)}
end end
end end
defp publish_smart_contract(address_hash, params, abi) do defp publish_smart_contract(address_hash, params, abi) do
address_hash attrs = address_hash |> attributes(params, abi)
|> attributes(params, abi)
|> Chain.create_smart_contract() Chain.create_smart_contract(attrs, attrs.external_libraries)
end end
defp unverified_smart_contract(address_hash, params, error) do defp unverified_smart_contract(address_hash, params, error) do
@ -64,6 +64,8 @@ defmodule Explorer.SmartContract.Publisher do
nil nil
end end
prepared_external_libraries = prepare_external_libraies(params["external_libraries"])
%{ %{
address_hash: address_hash, address_hash: address_hash,
name: params["name"], name: params["name"],
@ -73,11 +75,20 @@ defmodule Explorer.SmartContract.Publisher do
optimization: params["optimization"], optimization: params["optimization"],
contract_source_code: params["contract_source_code"], contract_source_code: params["contract_source_code"],
constructor_arguments: clean_constructor_arguments, constructor_arguments: clean_constructor_arguments,
external_libaries: params["external_libraries"], external_libraries: prepared_external_libraries,
abi: abi abi: abi
} }
end end
defp prepare_external_libraies(nil), do: []
defp prepare_external_libraies(map) do
map
|> Enum.map(fn {key, value} ->
%{name: key, address_hash: value}
end)
end
defp add_external_libraries(params, external_libraries) do defp add_external_libraries(params, external_libraries) do
clean_external_libraries = clean_external_libraries =
Enum.reduce(1..5, %{}, fn number, acc -> Enum.reduce(1..5, %{}, fn number, acc ->

@ -0,0 +1,23 @@
defmodule Explorer.SmartContract.PublisherWorker do
@moduledoc """
Background smart contract verification worker.
"""
use Que.Worker, concurrency: 5
alias Explorer.Chain.Events.Publisher, as: EventsPublisher
alias Explorer.SmartContract.Publisher
def perform({address_hash, params, external_libraries, conn}) do
result =
case Publisher.publish(address_hash, params, external_libraries) do
{:ok, _contract} = result ->
result
{:error, changeset} ->
{:error, changeset}
end
EventsPublisher.broadcast([{:contract_verification_result, {address_hash, result, conn}}], :on_demand)
end
end

@ -106,6 +106,7 @@ defmodule Explorer.Mixfile do
}, },
# bypass optional dependency # bypass optional dependency
{:plug_cowboy, "~> 2.0", only: [:dev, :test]}, {:plug_cowboy, "~> 2.0", only: [:dev, :test]},
{:que, "~> 0.10.1"},
{:sobelow, ">= 0.7.0", only: [:dev, :test], runtime: false}, {:sobelow, ">= 0.7.0", only: [:dev, :test], runtime: false},
# Tracing # Tracing
{:spandex, github: "spandex-project/spandex", branch: "allow-setting-trace-key", override: true}, {:spandex, github: "spandex-project/spandex", branch: "allow-setting-trace-key", override: true},

@ -0,0 +1,13 @@
defmodule Explorer.Repo.Migrations.AddExternalLibrariesToSmartContracts do
use Ecto.Migration
def change do
alter table(:smart_contracts) do
remove(:external_libraries)
end
alter table(:smart_contracts) do
add(:external_libraries, {:array, :map}, default: [])
end
end
end

@ -42,6 +42,7 @@
"ex_doc": {:hex, :ex_doc, "0.19.2", "6f4081ccd9ed081b6dc0bd5af97a41e87f5554de469e7d76025fba535180565f", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, "ex_doc": {:hex, :ex_doc, "0.19.2", "6f4081ccd9ed081b6dc0bd5af97a41e87f5554de469e7d76025fba535180565f", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_machina": {:hex, :ex_machina, "2.2.2", "d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, "ex_machina": {:hex, :ex_machina, "2.2.2", "d84217a6fb7840ff771d2561b8aa6d74a0d8968e4b10ecc0d7e9890dc8fb1c6a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
"ex_rlp": {:hex, :ex_rlp, "0.5.2", "7f4ce7bd55e543c054ce6d49629b01e9833c3462e3d547952be89865f39f2c58", [:mix], [], "hexpm"}, "ex_rlp": {:hex, :ex_rlp, "0.5.2", "7f4ce7bd55e543c054ce6d49629b01e9833c3462e3d547952be89865f39f2c58", [:mix], [], "hexpm"},
"ex_utils": {:hex, :ex_utils, "0.1.7", "2c133e0bcdc49a858cf8dacf893308ebc05bc5fba501dc3d2935e65365ec0bf3", [:mix], [], "hexpm"},
"exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], []}, "exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], []},
"excoveralls": {:git, "https://github.com/KronicDeth/excoveralls.git", "0a859b68851eeba9b43eba59fbc8f9098299cfe1", [branch: "circle-workflows"]}, "excoveralls": {:git, "https://github.com/KronicDeth/excoveralls.git", "0a859b68851eeba9b43eba59fbc8f9098299cfe1", [branch: "circle-workflows"]},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, optional: false]}]},
@ -66,6 +67,7 @@
"makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"math": {:hex, :math, "0.3.0", "e14e7291115201cb155a3567e66d196bf5088a6f55b030d598107d7ae934a11c", [:mix], []}, "math": {:hex, :math, "0.3.0", "e14e7291115201cb155a3567e66d196bf5088a6f55b030d598107d7ae934a11c", [:mix], []},
"meck": {:hex, :meck, "0.8.12", "1f7b1a9f5d12c511848fec26bbefd09a21e1432eadb8982d9a8aceb9891a3cf2", [:rebar3], [], "hexpm"}, "meck": {:hex, :meck, "0.8.12", "1f7b1a9f5d12c511848fec26bbefd09a21e1432eadb8982d9a8aceb9891a3cf2", [:rebar3], [], "hexpm"},
"memento": {:hex, :memento, "0.3.1", "b2909390820550d8b90b68ec96f9e15ff8a45a28b6f97fa4a62ef50e87c2f9d9", [:mix], [], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
@ -98,6 +100,7 @@
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"},
"prometheus_process_collector": {:hex, :prometheus_process_collector, "1.4.0", "6dbd39e3165b9ef1c94a7a820e9ffe08479f949dcdd431ed4aaea7b250eebfde", [:rebar3], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, "prometheus_process_collector": {:hex, :prometheus_process_collector, "1.4.0", "6dbd39e3165b9ef1c94a7a820e9ffe08479f949dcdd431ed4aaea7b250eebfde", [:rebar3], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"},
"qrcode": {:hex, :qrcode, "0.1.4", "544dc67ba42eed5ebce3d2a691d053387937740561d251f83f0a067917fae2dc", [:mix], [], "hexpm"}, "qrcode": {:hex, :qrcode, "0.1.4", "544dc67ba42eed5ebce3d2a691d053387937740561d251f83f0a067917fae2dc", [:mix], [], "hexpm"},
"que": {:hex, :que, "0.10.1", "788ed0ec92ed69bdf9cfb29bf41a94ca6355b8d44959bd0669cf706e557ac891", [:mix], [{:ex_utils, "~> 0.1.6", [hex: :ex_utils, repo: "hexpm", optional: false]}, {:memento, "~> 0.3.0", [hex: :memento, repo: "hexpm", optional: false]}], "hexpm"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"set_locale": {:git, "https://github.com/minifast/set_locale.git", "da9ae029642bc0fbd9212c2aaf86c0adca70c084", [branch: "master"]}, "set_locale": {:git, "https://github.com/minifast/set_locale.git", "da9ae029642bc0fbd9212c2aaf86c0adca70c084", [branch: "master"]},
"sobelow": {:hex, :sobelow, "0.7.4", "228cc6185b448b63ecc88429b43e864e8dd570e8e09f2d04b3aa71894db1bdbb", [:mix], [], "hexpm"}, "sobelow": {:hex, :sobelow, "0.7.4", "228cc6185b448b63ecc88429b43e864e8dd570e8e09f2d04b3aa71894db1bdbb", [:mix], [], "hexpm"},

Loading…
Cancel
Save