diff --git a/.dialyzer-ignore b/.dialyzer-ignore index 44a7f6862a..20e4865a42 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -13,8 +13,8 @@ lib/block_scout_web/schema/types.ex:31 lib/phoenix/router.ex:324 lib/phoenix/router.ex:402 lib/explorer/smart_contract/reader.ex:435 -lib/explorer/exchange_rates/source.ex:139 -lib/explorer/exchange_rates/source.ex:142 +lib/explorer/exchange_rates/source.ex:134 +lib/explorer/exchange_rates/source.ex:137 lib/indexer/fetcher/polygon_edge.ex:737 lib/indexer/fetcher/polygon_edge/deposit_execute.ex:140 lib/indexer/fetcher/polygon_edge/deposit_execute.ex:184 diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index 31e89c223f..8ec57498b3 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -72,7 +72,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps- @@ -130,7 +130,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -154,7 +154,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -183,7 +183,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -227,7 +227,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -253,7 +253,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -282,7 +282,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -330,7 +330,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -376,7 +376,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -438,7 +438,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -498,7 +498,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -569,7 +569,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" @@ -637,7 +637,7 @@ jobs: path: | deps _build - key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_27-${{ hashFiles('mix.lock') }} + key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_28-${{ hashFiles('mix.lock') }} restore-keys: | ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9200b4a88e..c464c468cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,15 @@ ## Current -- [#8924](https://github.com/blockscout/blockscout/pull/8924) - Delete invalid current token balances in OnDemand fetcher - ### Features +- [#8908](https://github.com/blockscout/blockscout/pull/8908) - Solidityscan report API endpoint - [#8900](https://github.com/blockscout/blockscout/pull/8900) - Add Compound proxy contract pattern - [#8611](https://github.com/blockscout/blockscout/pull/8611) - Implement sorting of smart contracts, address transactions ### Fixes +- [#8924](https://github.com/blockscout/blockscout/pull/8924) - Delete invalid current token balances in OnDemand fetcher - [#8922](https://github.com/blockscout/blockscout/pull/8922) - Allow call type to be in lowercase - [#8917](https://github.com/blockscout/blockscout/pull/8917) - Proxy detection hotfix in API v2 - [#8915](https://github.com/blockscout/blockscout/pull/8915) - smart-contract: delete embeds_many relation on replace diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex index 3fe7b47c26..3c68d73a09 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex @@ -12,9 +12,10 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do alias BlockScoutWeb.{AccessHelper, AddressView} alias Ecto.Association.NotLoaded alias Explorer.Chain - alias Explorer.Chain.SmartContract + alias Explorer.Chain.{Address, SmartContract} alias Explorer.SmartContract.{Reader, Writer} alias Explorer.SmartContract.Solidity.PublishHelper + alias Explorer.ThirdPartyIntegrations.SolidityScan @smart_contract_address_options [ necessity_by_association: %{ @@ -190,6 +191,48 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do end end + @doc """ + /api/v2/smart-contracts/${address_hash_string}/solidityscan-report logic + """ + @spec solidityscan_report(Plug.Conn.t(), map() | :atom) :: any() + def solidityscan_report(conn, %{"address_hash" => address_hash_string} = params) do + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, + {:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params), + {:ok, address} <- Chain.hash_to_address(address_hash), + {:is_smart_contract, true} <- {:is_smart_contract, Address.is_smart_contract(address)}, + response = SolidityScan.solidityscan_request(address_hash_string), + {:is_empty_response, false} <- {:is_empty_response, is_nil(response)} do + conn + |> put_status(200) + |> json(response) + else + {:format, :error} -> + conn + |> put_status(400) + |> json(%{status: "error", message: "Invalid address hash"}) + + {:restricted_access, true} -> + conn + |> put_status(403) + |> json(%{status: "error", message: "Access restricted"}) + + {:error, :not_found} -> + conn + |> put_status(404) + |> json(%{status: "error", message: "Address not found"}) + + {:is_smart_contract, false} -> + conn + |> put_status(404) + |> json(%{status: "error", message: "Smart-contract not found"}) + + {:is_empty_response, true} -> + conn + |> put_status(500) + |> json(%{status: "error", message: "Empty response"}) + end + end + def smart_contracts_list(conn, params) do full_options = [necessity_by_association: %{[address: :token] => :optional, [address: :names] => :optional, address: :required}] diff --git a/apps/block_scout_web/lib/block_scout_web/smart_contracts_api_v2_router.ex b/apps/block_scout_web/lib/block_scout_web/smart_contracts_api_v2_router.ex index d3f1d5e162..ad8bf8ad96 100644 --- a/apps/block_scout_web/lib/block_scout_web/smart_contracts_api_v2_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/smart_contracts_api_v2_router.ex @@ -27,6 +27,7 @@ defmodule BlockScoutWeb.SmartContractsApiV2Router do get("/:address_hash/methods-read-proxy", V2.SmartContractController, :methods_read_proxy) get("/:address_hash/methods-write-proxy", V2.SmartContractController, :methods_write_proxy) post("/:address_hash/query-read-method", V2.SmartContractController, :query_read_method) + get("/:address_hash/solidityscan-report", V2.SmartContractController, :solidityscan_report) get("/verification/config", V2.VerificationController, :config) diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex index 9b82e01ede..9c490d9131 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex @@ -51,7 +51,7 @@ defmodule BlockScoutWeb.API.V2.Helper do defp address_with_info(%Address{} = address, _address_hash) do %{ "hash" => Address.checksum(address), - "is_contract" => is_smart_contract(address), + "is_contract" => Address.is_smart_contract(address), "name" => address_name(address), "implementation_name" => implementation_name(address), "is_verified" => is_verified(address) @@ -94,11 +94,6 @@ defmodule BlockScoutWeb.API.V2.Helper do def implementation_name(_), do: nil - def is_smart_contract(%Address{contract_code: nil}), do: false - def is_smart_contract(%Address{contract_code: _}), do: true - def is_smart_contract(%NotLoaded{}), do: nil - def is_smart_contract(_), do: false - def is_verified(%Address{smart_contract: nil}), do: false def is_verified(%Address{smart_contract: %{metadata_from_verified_twin: true}}), do: false def is_verified(%Address{smart_contract: %NotLoaded{}}), do: nil diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex index c3e4d82887..ac8e395011 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex @@ -707,7 +707,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do _, skip_sc_check? ) do - if skip_sc_check? || Helper.is_smart_contract(to_address) do + if skip_sc_check? || Address.is_smart_contract(to_address) do "0x" <> Base.encode16(method_id, case: :lower) else nil @@ -760,7 +760,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do defp tx_types(%Transaction{to_address: to_address} = tx, types, :contract_call) do types = - if Helper.is_smart_contract(to_address) do + if Address.is_smart_contract(to_address) do [:contract_call | types] else types diff --git a/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex b/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex index 6022c87fcc..b20cd898ed 100644 --- a/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex +++ b/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex @@ -5,16 +5,16 @@ defmodule Explorer.Account.Notifier.ForbiddenAddress do import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0] + alias Explorer.Chain.Address + @blacklist [ burn_address_hash_string(), "0x000000000000000000000000000000000000dEaD" ] - alias Explorer.{AccessHelper, Repo} - alias Explorer.Chain.Token + alias Explorer.AccessHelper - import Ecto.Query, only: [from: 2] - import Explorer.Chain, only: [string_to_address_hash: 1] + import Explorer.Chain, only: [string_to_address_hash: 1, hash_to_address: 1] def check(address_string) when is_bitstring(address_string) do case format_address(address_string) do @@ -32,7 +32,7 @@ defmodule Explorer.Account.Notifier.ForbiddenAddress do {:error, "This address is blacklisted"} is_contract(address_hash) -> - {:error, "This address isn't personal"} + {:error, "This address isn't EOA"} match?({:restricted_access, true}, AccessHelper.restricted_access?(to_string(address_hash), %{})) -> {:error, "This address has restricted access"} @@ -43,14 +43,10 @@ defmodule Explorer.Account.Notifier.ForbiddenAddress do end defp is_contract(%Explorer.Chain.Hash{} = address_hash) do - query = - from( - token in Token, - where: token.contract_address_hash == ^address_hash - ) - - contract_addresses = Repo.all(query) - List.first(contract_addresses) + case hash_to_address(address_hash) do + {:error, :not_found} -> false + {:ok, address} -> Address.is_smart_contract(address) + end end defp format_address(address_hash_string) do diff --git a/apps/explorer/lib/explorer/chain/address.ex b/apps/explorer/lib/explorer/chain/address.ex index e8ea230059..96dc8c782c 100644 --- a/apps/explorer/lib/explorer/chain/address.ex +++ b/apps/explorer/lib/explorer/chain/address.ex @@ -7,6 +7,7 @@ defmodule Explorer.Chain.Address do use Explorer.Schema + alias Ecto.Association.NotLoaded alias Ecto.Changeset alias Explorer.{Chain, PagingOptions} @@ -332,6 +333,15 @@ defmodule Explorer.Chain.Address do end end + @doc """ + Checks if given address is smart-contract + """ + @spec is_smart_contract(any()) :: boolean() | nil + def is_smart_contract(%__MODULE__{contract_code: nil}), do: false + def is_smart_contract(%__MODULE__{contract_code: _}), do: true + def is_smart_contract(%NotLoaded{}), do: nil + def is_smart_contract(_), do: false + defp get_addresses(options) do accounts_with_n = fetch_top_addresses(options) diff --git a/apps/explorer/lib/explorer/exchange_rates/source.ex b/apps/explorer/lib/explorer/exchange_rates/source.ex index befa6560d0..1323cd1628 100644 --- a/apps/explorer/lib/explorer/exchange_rates/source.ex +++ b/apps/explorer/lib/explorer/exchange_rates/source.ex @@ -6,6 +6,7 @@ defmodule Explorer.ExchangeRates.Source do alias Explorer.Chain.Hash alias Explorer.ExchangeRates.Source.CoinGecko alias Explorer.ExchangeRates.Token + alias Explorer.Helper alias HTTPoison.{Error, Response} @doc """ @@ -91,12 +92,6 @@ defmodule Explorer.ExchangeRates.Source do [{"Content-Type", "application/json"}] end - def decode_json(data) do - Jason.decode!(data) - rescue - _ -> data - end - def to_decimal(nil), do: nil def to_decimal(%Decimal{} = value), do: value @@ -145,7 +140,7 @@ defmodule Explorer.ExchangeRates.Source do end defp parse_http_success_response(body) do - body_json = decode_json(body) + body_json = Helper.decode_json(body) cond do is_map(body_json) -> @@ -160,7 +155,7 @@ defmodule Explorer.ExchangeRates.Source do end defp parse_http_error_response(body) do - body_json = decode_json(body) + body_json = Helper.decode_json(body) if is_map(body_json) do {:error, body_json["error"]} diff --git a/apps/explorer/lib/explorer/helper.ex b/apps/explorer/lib/explorer/helper.ex index 5004b1f267..43b3dabd02 100644 --- a/apps/explorer/lib/explorer/helper.ex +++ b/apps/explorer/lib/explorer/helper.ex @@ -58,4 +58,14 @@ defmodule Explorer.Helper do Enum.map(list, fn el -> Map.put(el, preload_field, associated_elements[el[foreign_key_field]]) end) end + + @doc """ + Decode json with rescue + """ + @spec decode_json(any()) :: any() + def decode_json(data) do + Jason.decode!(data) + rescue + _ -> data + end end diff --git a/apps/explorer/lib/explorer/smart_contract/compiler_version.ex b/apps/explorer/lib/explorer/smart_contract/compiler_version.ex index e3d2bcde8a..248bfaa078 100644 --- a/apps/explorer/lib/explorer/smart_contract/compiler_version.ex +++ b/apps/explorer/lib/explorer/smart_contract/compiler_version.ex @@ -41,7 +41,7 @@ defmodule Explorer.SmartContract.CompilerVersion do {:ok, format_data(body, :solc)} {:ok, %{status_code: _status_code, body: body}} -> - {:error, decode_json(body)["error"]} + {:error, Helper.decode_json(body)["error"]} {:error, %{reason: reason}} -> {:error, reason} @@ -60,7 +60,7 @@ defmodule Explorer.SmartContract.CompilerVersion do {:ok, format_data(body, :vyper)} {:ok, %{status_code: _status_code, body: body}} -> - {:error, decode_json(body)["error"]} + {:error, Helper.decode_json(body)["error"]} {:error, %{reason: reason}} -> {:error, reason} @@ -140,10 +140,6 @@ defmodule Explorer.SmartContract.CompilerVersion do end end - defp decode_json(json) do - Jason.decode!(json) - end - @spec source_url(:solc | :vyper) :: String.t() defp source_url(compiler) do case compiler do diff --git a/apps/explorer/lib/explorer/third_party_integrations/solidityscan.ex b/apps/explorer/lib/explorer/third_party_integrations/solidityscan.ex new file mode 100644 index 0000000000..40a5bffb97 --- /dev/null +++ b/apps/explorer/lib/explorer/third_party_integrations/solidityscan.ex @@ -0,0 +1,40 @@ +defmodule Explorer.ThirdPartyIntegrations.SolidityScan do + @moduledoc """ + Module for SolidityScan integration https://apidoc.solidityscan.com/solidityscan-security-api/solidityscan-other-apis/quickscan-api-v1 + """ + + alias Explorer.Helper + + @blockscout_platform_id "16" + @recv_timeout 60_000 + + @doc """ + Proxy request to solidityscan API endpoint for the given smart-contract + """ + @spec solidityscan_request(String.t()) :: any() + def solidityscan_request(address_hash_string) do + headers = [{"Authorization", "Token #{api_key()}"}] + + url = base_url(address_hash_string) + + case HTTPoison.get(url, headers, recv_timeout: @recv_timeout) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + Helper.decode_json(body) + + _ -> + nil + end + end + + defp base_url(address_hash_string) do + "https://api.solidityscan.com/api/v1/quickscan/#{@blockscout_platform_id}/#{chain_id()}/#{address_hash_string}" + end + + defp chain_id do + Application.get_env(:explorer, __MODULE__)[:chain_id] + end + + defp api_key do + Application.get_env(:explorer, __MODULE__)[:api_key] + end +end diff --git a/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex b/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex index b510fb355d..95c22c84ce 100644 --- a/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex +++ b/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex @@ -4,6 +4,7 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do """ use Tesla + alias Explorer.Helper, as: ExplorerHelper alias Explorer.SmartContract.{Helper, RustVerifierInterface} alias HTTPoison.{Error, Response} alias Tesla.Multipart @@ -223,7 +224,7 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do end defp parse_verify_http_response(body) do - body_json = decode_json(body) + body_json = ExplorerHelper.decode_json(body) case body_json do # Success status from native Sourcify server @@ -246,7 +247,7 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do end defp parse_check_by_address_http_response(body) do - body_json = decode_json(body) + body_json = ExplorerHelper.decode_json(body) case body_json do [%{"status" => "perfect"}] -> @@ -264,11 +265,11 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do end defp parse_get_metadata_http_response(body) do - body_json = decode_json(body) + body_json = ExplorerHelper.decode_json(body) case body_json do %{"message" => message, "errors" => errors} -> - {:error, "#{message}: #{decode_json(errors)}"} + {:error, "#{message}: #{ExplorerHelper.decode_json(errors)}"} metadata -> {:ok, metadata} @@ -276,11 +277,11 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do end defp parse_get_metadata_any_http_response(body) do - body_json = decode_json(body) + body_json = ExplorerHelper.decode_json(body) case body_json do %{"message" => message, "errors" => errors} -> - {:error, "#{message}: #{decode_json(errors)}"} + {:error, "#{message}: #{ExplorerHelper.decode_json(errors)}"} %{"status" => status, "files" => metadata} -> {:ok, status, metadata} @@ -291,7 +292,7 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do end defp parse_http_error_response(body) do - body_json = decode_json(body) + body_json = ExplorerHelper.decode_json(body) if is_map(body_json) do {:error, body_json["error"]} @@ -350,7 +351,7 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do defp parse_json_from_sourcify_for_insertion(verification_metadata_json) do %{"name" => _, "content" => content} = verification_metadata_json - content_json = decode_json(content) + content_json = ExplorerHelper.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") @@ -401,12 +402,6 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do |> Map.put("contract_source_code", content) end - def decode_json(data) do - Jason.decode!(data) - rescue - _ -> data - end - defp config(module, key) do :explorer |> Application.get_env(module) diff --git a/config/runtime.exs b/config/runtime.exs index 81459925ee..0f1ed1aa86 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -368,6 +368,10 @@ config :explorer, Explorer.ThirdPartyIntegrations.Sourcify, chain_id: System.get_env("CHAIN_ID"), repo_url: System.get_env("SOURCIFY_REPO_URL") || "https://repo.sourcify.dev/contracts" +config :explorer, Explorer.ThirdPartyIntegrations.SolidityScan, + chain_id: System.get_env("SOLIDITYSCAN_CHAIN_ID"), + api_key: System.get_env("SOLIDITYSCAN_API_TOKEN") + enabled? = ConfigHelper.parse_bool_env_var("MICROSERVICE_SC_VERIFIER_ENABLED") # or "eth_bytecode_db" type = System.get_env("MICROSERVICE_SC_VERIFIER_TYPE", "sc_verifier") diff --git a/cspell.json b/cspell.json index b76de4bdc9..72bfc7609c 100644 --- a/cspell.json +++ b/cspell.json @@ -534,7 +534,18 @@ "zindex", "zipcode", "zkbob", - "zkevm" + "zkevm", + "erts", + "Asfpp", + "Nerg", + "secp", + "qwertyuioiuytrewertyuioiuytrertyuio", + "urlset", + "lastmod", + "qitmeer", + "meer", + "DefiLlama", + "SOLIDITYSCAN" ], "enableFiletypes": [ "dotenv",