From 9859c67d7fd3fa602d08aad99373633f8b666dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Sat, 12 Nov 2022 11:29:08 +0300 Subject: [PATCH 01/66] Add support for base64 encoded NFT metadata --- CHANGELOG.md | 1 + .../token/instance_metadata_retriever.ex | 36 ++++++++++++++++++- .../instance_metadata_retriever_test.exs | 21 +++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 691e3e752fdf..e58ca30136a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- [#6440](https://github.com/blockscout/blockscout/pull/6440) - Add support for base64 encoded NFT metadata - [#6407](https://github.com/blockscout/blockscout/pull/6407) - Indexed ratio for int txs fetching stage - [#6324](https://github.com/blockscout/blockscout/pull/6324) - Add verified contracts list page - [#6379](https://github.com/blockscout/blockscout/pull/6379) - API v2 for frontend diff --git a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex b/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex index d15e70de6684..daf6c4310985 100644 --- a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex +++ b/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex @@ -158,7 +158,7 @@ defmodule Explorer.Token.InstanceMetadataRetriever do def fetch_json(%{@uri => {:ok, ["data:application/json," <> json]}}, hex_token_id) do decoded_json = URI.decode(json) - fetch_json(%{@token_uri => {:ok, [decoded_json]}}, hex_token_id) + fetch_json(%{@uri => {:ok, [decoded_json]}}, hex_token_id) rescue e -> Logger.debug(["Unknown metadata format #{inspect(json)}. error #{inspect(e)}"], @@ -168,6 +168,40 @@ defmodule Explorer.Token.InstanceMetadataRetriever do {:error, json} end + def fetch_json(%{@token_uri => {:ok, ["data:application/json;base64," <> base64_encoded_json]}}, hex_token_id) do + case Base.url_decode64(base64_encoded_json) do + {:ok, base64_decoded} -> + fetch_json(%{@token_uri => {:ok, [base64_decoded]}}, hex_token_id) + + _ -> + {:error, base64_encoded_json} + end + rescue + e -> + Logger.debug(["Unknown metadata format base64 #{inspect(base64_encoded_json)}. error #{inspect(e)}"], + fetcher: :token_instances + ) + + {:error, base64_encoded_json} + end + + def fetch_json(%{@uri => {:ok, ["data:application/json;base64," <> base64_encoded_json]}}, hex_token_id) do + case Base.url_decode64(base64_encoded_json) do + {:ok, base64_decoded} -> + fetch_json(%{@uri => {:ok, [base64_decoded]}}, hex_token_id) + + _ -> + {:error, base64_encoded_json} + end + rescue + e -> + Logger.debug(["Unknown metadata format base64 #{inspect(base64_encoded_json)}. error #{inspect(e)}"], + fetcher: :token_instances + ) + + {:error, base64_encoded_json} + end + def fetch_json(%{@token_uri => {:ok, ["ipfs://ipfs/" <> ipfs_uid]}}, hex_token_id) do ipfs_url = "https://ipfs.io/ipfs/" <> ipfs_uid fetch_metadata_inner(ipfs_url, hex_token_id) diff --git a/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs b/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs index 8376b7c595ac..9ab3971f08f0 100644 --- a/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs +++ b/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs @@ -286,5 +286,26 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do } }} end + + test "decodes base64 encoded json file in tokenURI" do + data = %{ + "c87b56dd" => + {:ok, + [ + "data:application/json;base64,eyJuYW1lIjogIi54ZGFpIiwgImRlc2NyaXB0aW9uIjogIlB1bmsgRG9tYWlucyBkaWdpdGFsIGlkZW50aXR5LiBWaXNpdCBodHRwczovL3B1bmsuZG9tYWlucy8iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhacFpYZENiM2c5SWpBZ01DQTFNREFnTlRBd0lpQjNhV1IwYUQwaU5UQXdJaUJvWldsbmFIUTlJalV3TUNJK1BHUmxabk0rUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKbmNtRmtJaUI0TVQwaU1DVWlJSGt4UFNJd0pTSWdlREk5SWpFd01DVWlJSGt5UFNJd0pTSStQSE4wYjNBZ2IyWm1jMlYwUFNJd0pTSWdjM1I1YkdVOUluTjBiM0F0WTI5c2IzSTZjbWRpS0RVNExERTNMREV4TmlrN2MzUnZjQzF2Y0dGamFYUjVPakVpSUM4K1BITjBiM0FnYjJabWMyVjBQU0l4TURBbElpQnpkSGxzWlQwaWMzUnZjQzFqYjJ4dmNqcHlaMklvTVRFMkxESTFMREUzS1R0emRHOXdMVzl3WVdOcGRIazZNU0lnTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp3dlpHVm1jejQ4Y21WamRDQjRQU0l3SWlCNVBTSXdJaUIzYVdSMGFEMGlOVEF3SWlCb1pXbG5hSFE5SWpVd01DSWdabWxzYkQwaWRYSnNLQ05uY21Ga0tTSXZQangwWlhoMElIZzlJalV3SlNJZ2VUMGlOVEFsSWlCa2IyMXBibUZ1ZEMxaVlYTmxiR2x1WlQwaWJXbGtaR3hsSWlCbWFXeHNQU0ozYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMXphWHBsUFNKNExXeGhjbWRsSWo0dWVHUmhhVHd2ZEdWNGRENDhkR1Y0ZENCNFBTSTFNQ1VpSUhrOUlqY3dKU0lnWkc5dGFXNWhiblF0WW1GelpXeHBibVU5SW0xcFpHUnNaU0lnWm1sc2JEMGlkMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlQbkIxYm1zdVpHOXRZV2x1Y3p3dmRHVjRkRDQ4TDNOMlp6ND0ifQ==" + ]} + } + + assert InstanceMetadataRetriever.fetch_json(data) == + {:ok, + %{ + metadata: %{ + "name" => ".xdai", + "description" => "Punk Domains digital identity. Visit https://punk.domains/", + "image" => + "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAgNTAwIiB3aWR0aD0iNTAwIiBoZWlnaHQ9IjUwMCI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjEwMCUiIHkyPSIwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3R5bGU9InN0b3AtY29sb3I6cmdiKDU4LDE3LDExNik7c3RvcC1vcGFjaXR5OjEiIC8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdHlsZT0ic3RvcC1jb2xvcjpyZ2IoMTE2LDI1LDE3KTtzdG9wLW9wYWNpdHk6MSIgLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iNTAwIiBoZWlnaHQ9IjUwMCIgZmlsbD0idXJsKCNncmFkKSIvPjx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBkb21pbmFudC1iYXNlbGluZT0ibWlkZGxlIiBmaWxsPSJ3aGl0ZSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1zaXplPSJ4LWxhcmdlIj4ueGRhaTwvdGV4dD48dGV4dCB4PSI1MCUiIHk9IjcwJSIgZG9taW5hbnQtYmFzZWxpbmU9Im1pZGRsZSIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPnB1bmsuZG9tYWluczwvdGV4dD48L3N2Zz4=" + } + }} + end end end From a032cae0bd30c5403291104130c0c313dac8a28e Mon Sep 17 00:00:00 2001 From: Qwerty5Uiop Date: Wed, 16 Nov 2022 11:13:56 +0400 Subject: [PATCH 02/66] Coin balances and tx receipts batch size and concurrency envs --- CHANGELOG.md | 1 + .../lib/indexer/fetcher/coin_balance.ex | 21 ++++++++++++------- .../indexer/fetcher/internal_transaction.ex | 4 ++-- config/runtime.exs | 15 +++++++++++++ docker-compose/envs/common-blockscout.env | 4 ++++ docker/Makefile | 12 +++++++++++ 6 files changed, 47 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cabe874c457f..aee83dc0591d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - [#6391](https://github.com/blockscout/blockscout/pull/6391), [#6427](https://github.com/blockscout/blockscout/pull/6427) - TokenTransfer token_id -> token_ids migration - [#6443](https://github.com/blockscout/blockscout/pull/6443) - Drop internal transactions order index - [#6450](https://github.com/blockscout/blockscout/pull/6450) - INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE and INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY env variables +- [#6454](https://github.com/blockscout/blockscout/pull/6454) - INDEXER_RECEIPTS_BATCH_SIZE, INDEXER_RECEIPTS_CONCURRENCY, INDEXER_COIN_BALANCES_BATCH_SIZE, INDEXER_COIN_BALANCES_CONCURRENCY env variables ### Fixes diff --git a/apps/indexer/lib/indexer/fetcher/coin_balance.ex b/apps/indexer/lib/indexer/fetcher/coin_balance.ex index 7b175c7915b3..1350e0c7ef7d 100644 --- a/apps/indexer/lib/indexer/fetcher/coin_balance.ex +++ b/apps/indexer/lib/indexer/fetcher/coin_balance.ex @@ -20,13 +20,8 @@ defmodule Indexer.Fetcher.CoinBalance do @behaviour BufferedTask - @defaults [ - flush_interval: :timer.seconds(3), - max_batch_size: 500, - max_concurrency: 4, - task_supervisor: Indexer.Fetcher.CoinBalance.TaskSupervisor, - metadata: [fetcher: :coin_balance] - ] + @default_max_batch_size 500 + @default_max_concurrency 4 @doc """ Asynchronously fetches balances for each address `hash` at the `block_number`. @@ -56,7 +51,7 @@ defmodule Indexer.Fetcher.CoinBalance do end merged_init_options = - @defaults + defaults() |> Keyword.merge(mergeable_init_options) |> Keyword.put(:state, state) @@ -264,4 +259,14 @@ defmodule Indexer.Fetcher.CoinBalance do end end) end + + defp defaults do + [ + flush_interval: :timer.seconds(3), + max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size, + max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency, + task_supervisor: Indexer.Fetcher.CoinBalance.TaskSupervisor, + metadata: [fetcher: :coin_balance] + ] + end end diff --git a/apps/indexer/lib/indexer/fetcher/internal_transaction.ex b/apps/indexer/lib/indexer/fetcher/internal_transaction.ex index dba1ed36f893..13005c530ef9 100644 --- a/apps/indexer/lib/indexer/fetcher/internal_transaction.ex +++ b/apps/indexer/lib/indexer/fetcher/internal_transaction.ex @@ -32,10 +32,10 @@ defmodule Indexer.Fetcher.InternalTransaction do Internal transactions are an expensive upstream operation. The number of results to fetch is configured by `@max_batch_size` and represents the number of transaction hashes to request internal transactions in a single JSONRPC - request. Defaults to `#{@max_batch_size}`. + request. Defaults to `#{@default_max_batch_size}`. The `@max_concurrency` attribute configures the number of concurrent requests - of `@max_batch_size` to allow against the JSONRPC. Defaults to `#{@max_concurrency}`. + of `@max_batch_size` to allow against the JSONRPC. Defaults to `#{@default_max_concurrency}`. *Note*: The internal transactions for individual transactions cannot be paginated, so the total number of internal transactions that could be produced is unknown. diff --git a/config/runtime.exs b/config/runtime.exs index 50cd63f2b08b..d4f6f958eb9b 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -405,6 +405,13 @@ config :indexer, trace_last_block: System.get_env("TRACE_LAST_BLOCK") || "", fetch_rewards_way: System.get_env("FETCH_REWARDS_WAY", "trace_block") +{receipts_batch_size, _} = Integer.parse(System.get_env("INDEXER_RECEIPTS_BATCH_SIZE", "250")) +{receipts_concurrency, _} = Integer.parse(System.get_env("INDEXER_RECEIPTS_CONCURRENCY", "10")) + +config :indexer, + receipts_batch_size: receipts_batch_size, + receipts_concurrency: receipts_concurrency + config :indexer, Indexer.Fetcher.PendingTransaction.Supervisor, disabled?: System.get_env("ETHEREUM_JSONRPC_VARIANT") == "besu" || @@ -477,6 +484,14 @@ config :indexer, Indexer.Fetcher.InternalTransaction, batch_size: internal_transaction_fetcher_batch_size, concurrency: internal_transaction_fetcher_concurrency +{coin_balance_fetcher_batch_size, _} = Integer.parse(System.get_env("INDEXER_COIN_BALANCES_BATCH_SIZE", "500")) + +{coin_balance_fetcher_concurrency, _} = Integer.parse(System.get_env("INDEXER_COIN_BALANCES_CONCURRENCY", "4")) + +config :indexer, Indexer.Fetcher.CoinBalance, + batch_size: coin_balance_fetcher_batch_size, + concurrency: coin_balance_fetcher_concurrency + Code.require_file("#{config_env()}.exs", "config/runtime") for config <- "../apps/*/config/runtime/#{config_env()}.exs" |> Path.expand(__DIR__) |> Path.wildcard() do diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env index cffb1aac85e9..b0d3c84156cf 100644 --- a/docker-compose/envs/common-blockscout.env +++ b/docker-compose/envs/common-blockscout.env @@ -86,6 +86,10 @@ INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER=false # INDEXER_CATCHUP_BLOCKS_CONCURRENCY= # INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE= # INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY= +# INDEXER_COIN_BALANCES_BATCH_SIZE= +# INDEXER_COIN_BALANCES_CONCURRENCY= +# INDEXER_RECEIPTS_BATCH_SIZE= +# INDEXER_RECEIPTS_CONCURRENCY= # TOKEN_ID_MIGRATION_FIRST_BLOCK= # TOKEN_ID_MIGRATION_CONCURRENCY= # TOKEN_ID_MIGRATION_BATCH_SIZE= diff --git a/docker/Makefile b/docker/Makefile index 8382fdbdbd82..c38684bae11e 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -460,6 +460,18 @@ endif ifdef INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY=$(INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY)' endif +ifdef INDEXER_COIN_BALANCES_BATCH_SIZE + BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_RECEIPTS_BATCH_SIZE=$(INDEXER_RECEIPTS_BATCH_SIZE)' +endif +ifdef INDEXER_COIN_BALANCES_CONCURRENCY + BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_RECEIPTS_CONCURRENCY=$(INDEXER_RECEIPTS_CONCURRENCY)' +endif +ifdef INDEXER_RECEIPTS_BATCH_SIZE + BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_RECEIPTS_BATCH_SIZE=$(INDEXER_RECEIPTS_BATCH_SIZE)' +endif +ifdef INDEXER_RECEIPTS_CONCURRENCY + BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_RECEIPTS_CONCURRENCY=$(INDEXER_RECEIPTS_CONCURRENCY)' +endif ifdef INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE=$(INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE)' endif From 1ced663fbe13f1ce6861230b38437873a13f6e52 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 09:20:44 +0000 Subject: [PATCH 03/66] Bump loader-utils from 2.0.3 to 2.0.4 in /apps/block_scout_web/assets Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/webpack/loader-utils/releases) - [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md) - [Commits](https://github.com/webpack/loader-utils/compare/v2.0.3...v2.0.4) --- updated-dependencies: - dependency-name: loader-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index de09d5d394d1..4865bf888711 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -12327,9 +12327,9 @@ } }, "node_modules/loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "dependencies": { "big.js": "^5.2.2", @@ -27802,9 +27802,9 @@ "dev": true }, "loader-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz", - "integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "requires": { "big.js": "^5.2.2", From 59ac2914e3759827b1a1a86c0d46466df15a3b1a Mon Sep 17 00:00:00 2001 From: Viktor Baranov Date: Wed, 16 Nov 2022 18:14:34 +0300 Subject: [PATCH 04/66] Add support for yul verification via rust microservice --- .dialyzer-ignore | 2 +- CHANGELOG.md | 1 + .../templates/address_contract/index.html.eex | 26 +++--- .../_yul_contracts_switcher.html.eex | 21 +++++ .../new.html.eex | 4 + .../new.html.eex | 6 +- ...ct_verification_via_flattened_code_view.ex | 1 + ..._verification_via_multi_part_files_view.ex | 1 + .../views/address_contract_view.ex | 2 +- .../lib/block_scout_web/views/address_view.ex | 4 +- .../views/tokens/instance/overview_view.ex | 2 +- .../views/tokens/overview_view.ex | 4 +- apps/block_scout_web/priv/gettext/default.pot | 92 ++++++++++++------- .../priv/gettext/en/LC_MESSAGES/default.po | 92 ++++++++++++------- .../lib/explorer/chain/smart_contract.ex | 10 +- .../smart_contract/solidity/publisher.ex | 5 +- .../smart_contract/solidity/verifier.ex | 8 +- ...53_remove_not_null_constraint_from_abi.exs | 7 ++ 18 files changed, 190 insertions(+), 98 deletions(-) create mode 100644 apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex create mode 100644 apps/explorer/priv/repo/migrations/20221114113853_remove_not_null_constraint_from_abi.exs diff --git a/.dialyzer-ignore b/.dialyzer-ignore index 654d998e12d8..7c287bf3b506 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -22,7 +22,7 @@ lib/explorer/smart_contract/reader.ex:435 lib/indexer/fetcher/token_total_supply_on_demand.ex:16 lib/explorer/exchange_rates/source.ex:116 lib/explorer/exchange_rates/source.ex:119 -lib/explorer/smart_contract/solidity/verifier.ex:310 +lib/explorer/smart_contract/solidity/verifier.ex:316 lib/block_scout_web/templates/address_contract/index.html.eex:158 lib/block_scout_web/templates/address_contract/index.html.eex:195 lib/explorer/third_party_integrations/sourcify.ex:120 diff --git a/CHANGELOG.md b/CHANGELOG.md index 01551628f4c0..e2d071188be2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- [#6444](https://github.com/blockscout/blockscout/pull/6444) - Add support for yul verification via rust microservice - [#6440](https://github.com/blockscout/blockscout/pull/6440) - Add support for base64 encoded NFT metadata - [#6407](https://github.com/blockscout/blockscout/pull/6407) - Indexed ratio for int txs fetching stage - [#6324](https://github.com/blockscout/blockscout/pull/6324) - Add verified contracts list page diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index f3b11b67071f..a5956a5dcadf 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -117,18 +117,20 @@ <% end)%> -
-
-

<%= gettext "Contract ABI" %>

- -
-
-
<%= format_smart_contract_abi(target_contract.abi) %>
-            
-
-
+ <%= if !is_nil(target_contract.abi) do %>> +
+
+

<%= gettext "Contract ABI" %>

+ +
+
+
<%= format_smart_contract_abi(target_contract.abi) %>
+              
+
+
+ <% end %> <% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex new file mode 100644 index 000000000000..f7b212d4afb0 --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex @@ -0,0 +1,21 @@ +
+
+ <%= label @f, "Is yul contract" %> +
+
+
+ <%= radio_button @f, :is_yul, false, class: "form-check-input autodetectfalse" %> +
+ <%= label :is_yul, :false, gettext("No"), class: "radio-text" %> +
+
+ <%= radio_button @f, :is_yul, true, class: "form-check-input autodetecttrue", "aria-describedby": "is_yul-help-block" %> +
+ <%= label :is_yul, :true, gettext("Yes"), class: "radio-text" %> +
+
+ <%= error_tag @f, :is_yul, id: "is_yul-help-block", class: "text-danger form-error" %> +
+
<%= gettext("Select Yes if you want to vefify Yul contract.") %>
+
+
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex index 77285371dc1a..9eec8b7d7ba0 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex @@ -15,6 +15,10 @@ <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_contract_address_field.html", f: f %> + <%= if RustVerifierInterface.enabled?() do %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_yul_contracts_switcher.html", f: f %> + <% end %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_contract_name_field.html", f: f, tooltip: gettext "Must match the name specified in the code. For example, in contract MyContract {..} MyContract is the contract name." %> <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_include_nightly_builds_field.html", f: f %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex index 1cee4b5c11cd..c5a9e46819d5 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex @@ -4,7 +4,7 @@ <%= render BlockScoutWeb.CommonComponentsView, "_channel_disconnected_message.html", text: gettext("Connection Lost") %>
-

<%= gettext "New Solidity Smart Contract Verification" %>

+

<%= if RustVerifierInterface.enabled?(), do: gettext "New Solidity/Yul Smart Contract Verification", else: gettext "New Solidity Smart Contract Verification" %>

<%= form_for changeset, address_contract_verification_path(@conn, :create), @@ -60,7 +60,7 @@
- +
@@ -69,7 +69,7 @@
-
<%= gettext "Drop all Solidity contract source files into the drop zone." %>
+
<%= if RustVerifierInterface.enabled?(), do: gettext "Drop all Solidity or Yul contract source files into the drop zone.", else: gettext "Drop all Solidity contract source files into the drop zone." %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_flattened_code_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_flattened_code_view.ex index 3a120c597f19..f6e676d7fcdf 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_flattened_code_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_flattened_code_view.ex @@ -3,4 +3,5 @@ defmodule BlockScoutWeb.AddressContractVerificationViaFlattenedCodeView do alias Explorer.Chain alias Explorer.Chain.SmartContract + alias Explorer.SmartContract.RustVerifierInterface end diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_multi_part_files_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_multi_part_files_view.ex index 7ec8e9b7d989..12a80e5eb282 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_multi_part_files_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_contract_verification_via_multi_part_files_view.ex @@ -3,4 +3,5 @@ defmodule BlockScoutWeb.AddressContractVerificationViaMultiPartFilesView do alias Explorer.Chain alias Explorer.Chain.SmartContract + alias Explorer.SmartContract.RustVerifierInterface end diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex index 8856d14c3045..ce7b4dc00ba1 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex @@ -130,7 +130,7 @@ defmodule BlockScoutWeb.AddressContractView do end def creation_code(%Address{contracts_creation_internal_transaction: %InternalTransaction{}} = address) do - address.contracts_creation_internal_transaction.input + address.contracts_creation_internal_transaction.init end def creation_code(%Address{contracts_creation_transaction: %Transaction{}} = address) do diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex index 8fff82fb893b..50f54e6b2bea 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex @@ -247,7 +247,7 @@ defmodule BlockScoutWeb.AddressView do def smart_contract_verified?(%Address{smart_contract: nil}), do: false def smart_contract_with_read_only_functions?(%Address{smart_contract: %SmartContract{}} = address) do - Enum.any?(address.smart_contract.abi, &is_read_function?(&1)) + Enum.any?(address.smart_contract.abi || [], &is_read_function?(&1)) end def smart_contract_with_read_only_functions?(%Address{smart_contract: nil}), do: false @@ -262,7 +262,7 @@ defmodule BlockScoutWeb.AddressView do def smart_contract_with_write_functions?(%Address{smart_contract: %SmartContract{}} = address) do Enum.any?( - address.smart_contract.abi, + address.smart_contract.abi || [], &Writer.write_function?(&1) ) end diff --git a/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex b/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex index 4a25a937fdc8..1c0c748dc415 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex @@ -122,7 +122,7 @@ defmodule BlockScoutWeb.Tokens.Instance.OverviewView do def smart_contract_with_read_only_functions?( %Token{contract_address: %Address{smart_contract: %SmartContract{}}} = token ) do - Enum.any?(token.contract_address.smart_contract.abi, &Helper.queriable_method?(&1)) + Enum.any?(token.contract_address.smart_contract.abi || [], &Helper.queriable_method?(&1)) end def smart_contract_with_read_only_functions?(%Token{contract_address: %Address{smart_contract: nil}}), do: false diff --git a/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex b/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex index e258938f1b95..473c2df3e2e1 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex @@ -48,7 +48,7 @@ defmodule BlockScoutWeb.Tokens.OverviewView do def smart_contract_with_read_only_functions?( %Token{contract_address: %Address{smart_contract: %SmartContract{}}} = token ) do - Enum.any?(token.contract_address.smart_contract.abi, &Helper.queriable_method?(&1)) + Enum.any?(token.contract_address.smart_contract.abi || [], &Helper.queriable_method?(&1)) end def smart_contract_with_read_only_functions?(%Token{contract_address: %Address{smart_contract: nil}}), do: false @@ -63,7 +63,7 @@ defmodule BlockScoutWeb.Tokens.OverviewView do contract_address: %Address{smart_contract: %SmartContract{}} = address }) do Enum.any?( - address.smart_contract.abi, + address.smart_contract.abi || [], &Writer.write_function?(&1) ) end diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 80848119c5e7..e28e09fdfcb7 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -176,7 +176,7 @@ msgstr "" msgid "Add API key" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:82 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:86 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:76 #, elixir-autogen, elixir-format msgid "Add Contract Libraries" @@ -187,7 +187,7 @@ msgstr "" msgid "Add Custom ABI" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:93 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:97 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:87 #, elixir-autogen, elixir-format msgid "Add Library" @@ -502,7 +502,7 @@ msgstr "" #: lib/block_scout_web/templates/account/public_tags_request/form.html.eex:62 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:120 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:111 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:115 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:41 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:107 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:55 @@ -640,7 +640,7 @@ msgstr "" msgid "Contract" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:122 +#: lib/block_scout_web/templates/address_contract/index.html.eex:123 #, elixir-autogen, elixir-format msgid "Contract ABI" msgstr "" @@ -670,13 +670,13 @@ msgstr "" msgid "Contract Creation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:138 -#: lib/block_scout_web/templates/address_contract/index.html.eex:153 +#: lib/block_scout_web/templates/address_contract/index.html.eex:140 +#: lib/block_scout_web/templates/address_contract/index.html.eex:155 #, elixir-autogen, elixir-format msgid "Contract Creation Code" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:86 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:90 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:80 #, elixir-autogen, elixir-format msgid "Contract Libraries" @@ -704,7 +704,7 @@ msgstr "" msgid "Contract source code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:144 +#: lib/block_scout_web/templates/address_contract/index.html.eex:146 #, elixir-autogen, elixir-format msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -714,7 +714,7 @@ msgstr "" msgid "Contribute" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:124 +#: lib/block_scout_web/templates/address_contract/index.html.eex:125 #, elixir-autogen, elixir-format msgid "Copy ABI" msgstr "" @@ -746,8 +746,8 @@ msgstr "" msgid "Copy Contract Address" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:140 -#: lib/block_scout_web/templates/address_contract/index.html.eex:156 +#: lib/block_scout_web/templates/address_contract/index.html.eex:142 +#: lib/block_scout_web/templates/address_contract/index.html.eex:158 #, elixir-autogen, elixir-format msgid "Copy Contract Creation Code" msgstr "" @@ -757,8 +757,8 @@ msgstr "" msgid "Copy Decompiled Contract Code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:177 -#: lib/block_scout_web/templates/address_contract/index.html.eex:187 +#: lib/block_scout_web/templates/address_contract/index.html.eex:179 +#: lib/block_scout_web/templates/address_contract/index.html.eex:189 #, elixir-autogen, elixir-format msgid "Copy Deployed ByteCode" msgstr "" @@ -966,8 +966,8 @@ msgstr "" msgid "Delegate Call" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:175 -#: lib/block_scout_web/templates/address_contract/index.html.eex:183 +#: lib/block_scout_web/templates/address_contract/index.html.eex:177 +#: lib/block_scout_web/templates/address_contract/index.html.eex:185 #, elixir-autogen, elixir-format msgid "Deployed ByteCode" msgstr "" @@ -997,7 +997,7 @@ msgstr "" msgid "Difficulty" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:145 +#: lib/block_scout_web/templates/address_contract/index.html.eex:147 #, elixir-autogen, elixir-format msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1073,13 +1073,13 @@ msgid "ETH RPC API Documentation" msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:76 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:26 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:22 #, elixir-autogen, elixir-format msgid "EVM Version" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:34 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:26 #, elixir-autogen, elixir-format msgid "EVM version details" @@ -1117,7 +1117,7 @@ msgstr "" msgid "Emission Reward" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:68 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:72 #, elixir-autogen, elixir-format msgid "Enter the Solidity Contract Code" msgstr "" @@ -1190,7 +1190,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:212 +#: lib/block_scout_web/templates/address_contract/index.html.eex:214 #, elixir-autogen, elixir-format msgid "External libraries" msgstr "" @@ -1373,7 +1373,7 @@ msgstr "" msgid "If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:52 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:56 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:48 #, elixir-autogen, elixir-format msgid "If you enabled optimization during compilation, select yes." @@ -1510,7 +1510,7 @@ msgid "Loading chart..." msgstr "" #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:77 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:105 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:109 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:35 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:99 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:49 @@ -1649,7 +1649,7 @@ msgstr "" msgid "Must be set to:" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:18 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:22 #, elixir-autogen, elixir-format msgid "Must match the name specified in the code. For example, in contract MyContract {..} MyContract is the contract name." msgstr "" @@ -1733,7 +1733,8 @@ msgstr "" #: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:9 #: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:9 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:42 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:9 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:46 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:38 #, elixir-autogen, elixir-format msgid "No" @@ -1802,7 +1803,7 @@ msgid "Optimization enabled" msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:70 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:58 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:62 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:54 #, elixir-autogen, elixir-format msgid "Optimization runs" @@ -1825,7 +1826,7 @@ msgstr "" msgid "Owner Address" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:73 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:77 #, elixir-autogen, elixir-format msgid "POA solidity flattener or the" msgstr "" @@ -2041,7 +2042,7 @@ msgstr "" msgid "Request to edit a public tag/label" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:108 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:112 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:38 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:104 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:52 @@ -2293,7 +2294,7 @@ msgstr "" msgid "The 0x library address. This can be found in the generated json file or Truffle output (if using truffle)." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:34 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:26 #, elixir-autogen, elixir-format msgid "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." @@ -2309,7 +2310,7 @@ msgstr "" msgid "The block height of a particular block is defined as the number of blocks preceding it in the blockchain." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:22 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:26 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:18 #, elixir-autogen, elixir-format msgid "The compiler version is specified in pragma solidity X.X.X. Use the compiler version rather than the nightly build. If using the Solidity compiler, run solc —version to check." @@ -2929,14 +2930,14 @@ msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:27 #: lib/block_scout_web/templates/address_contract/index.html.eex:29 -#: lib/block_scout_web/templates/address_contract/index.html.eex:161 -#: lib/block_scout_web/templates/address_contract/index.html.eex:192 +#: lib/block_scout_web/templates/address_contract/index.html.eex:163 +#: lib/block_scout_web/templates/address_contract/index.html.eex:194 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 #, elixir-autogen, elixir-format msgid "Verify & Publish" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:107 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:111 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:37 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:103 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:51 @@ -3061,7 +3062,7 @@ msgstr "" msgid "Watch list" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:73 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:77 #, elixir-autogen, elixir-format msgid "We recommend using flattened code. This is necessary if your code utilizes a library or inherits dependencies. Use the" msgstr "" @@ -3092,7 +3093,8 @@ msgstr "" #: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:14 #: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:14 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:47 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:14 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:51 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:43 #, elixir-autogen, elixir-format msgid "Yes" @@ -3249,7 +3251,7 @@ msgstr "" msgid "true" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:73 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:77 #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" @@ -3424,3 +3426,23 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Blocks With Internal Transactions Indexed" msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:72 +#, elixir-autogen, elixir-format +msgid "Drop all Solidity or Yul contract source files into the drop zone." +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:7 +#, elixir-autogen, elixir-format +msgid "New Solidity/Yul Smart Contract Verification" +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select Yes if you want to vefify Yul contract." +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63 +#, elixir-autogen, elixir-format +msgid "Sources *.sol or *.yul files" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 238b7ca0d25e..5b35d4bbe42b 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -176,7 +176,7 @@ msgstr "" msgid "Add API key" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:82 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:86 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:76 #, elixir-autogen, elixir-format msgid "Add Contract Libraries" @@ -187,7 +187,7 @@ msgstr "" msgid "Add Custom ABI" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:93 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:97 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:87 #, elixir-autogen, elixir-format msgid "Add Library" @@ -502,7 +502,7 @@ msgstr "" #: lib/block_scout_web/templates/account/public_tags_request/form.html.eex:62 #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:120 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:111 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:115 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:41 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:107 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:55 @@ -640,7 +640,7 @@ msgstr "" msgid "Contract" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:122 +#: lib/block_scout_web/templates/address_contract/index.html.eex:123 #, elixir-autogen, elixir-format msgid "Contract ABI" msgstr "" @@ -670,13 +670,13 @@ msgstr "" msgid "Contract Creation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:138 -#: lib/block_scout_web/templates/address_contract/index.html.eex:153 +#: lib/block_scout_web/templates/address_contract/index.html.eex:140 +#: lib/block_scout_web/templates/address_contract/index.html.eex:155 #, elixir-autogen, elixir-format msgid "Contract Creation Code" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:86 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:90 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:80 #, elixir-autogen, elixir-format msgid "Contract Libraries" @@ -704,7 +704,7 @@ msgstr "" msgid "Contract source code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:144 +#: lib/block_scout_web/templates/address_contract/index.html.eex:146 #, elixir-autogen, elixir-format msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -714,7 +714,7 @@ msgstr "" msgid "Contribute" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:124 +#: lib/block_scout_web/templates/address_contract/index.html.eex:125 #, elixir-autogen, elixir-format msgid "Copy ABI" msgstr "" @@ -746,8 +746,8 @@ msgstr "" msgid "Copy Contract Address" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:140 -#: lib/block_scout_web/templates/address_contract/index.html.eex:156 +#: lib/block_scout_web/templates/address_contract/index.html.eex:142 +#: lib/block_scout_web/templates/address_contract/index.html.eex:158 #, elixir-autogen, elixir-format msgid "Copy Contract Creation Code" msgstr "" @@ -757,8 +757,8 @@ msgstr "" msgid "Copy Decompiled Contract Code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:177 -#: lib/block_scout_web/templates/address_contract/index.html.eex:187 +#: lib/block_scout_web/templates/address_contract/index.html.eex:179 +#: lib/block_scout_web/templates/address_contract/index.html.eex:189 #, elixir-autogen, elixir-format msgid "Copy Deployed ByteCode" msgstr "" @@ -966,8 +966,8 @@ msgstr "" msgid "Delegate Call" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:175 -#: lib/block_scout_web/templates/address_contract/index.html.eex:183 +#: lib/block_scout_web/templates/address_contract/index.html.eex:177 +#: lib/block_scout_web/templates/address_contract/index.html.eex:185 #, elixir-autogen, elixir-format msgid "Deployed ByteCode" msgstr "" @@ -997,7 +997,7 @@ msgstr "" msgid "Difficulty" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:145 +#: lib/block_scout_web/templates/address_contract/index.html.eex:147 #, elixir-autogen, elixir-format msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1073,13 +1073,13 @@ msgid "ETH RPC API Documentation" msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:76 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:26 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:22 #, elixir-autogen, elixir-format msgid "EVM Version" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:34 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:26 #, elixir-autogen, elixir-format msgid "EVM version details" @@ -1117,7 +1117,7 @@ msgstr "" msgid "Emission Reward" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:68 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:72 #, elixir-autogen, elixir-format msgid "Enter the Solidity Contract Code" msgstr "" @@ -1190,7 +1190,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:212 +#: lib/block_scout_web/templates/address_contract/index.html.eex:214 #, elixir-autogen, elixir-format msgid "External libraries" msgstr "" @@ -1373,7 +1373,7 @@ msgstr "" msgid "If it still does not show up after 1 hour, please check with your sender/exchange/wallet/transaction provider for additional information." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:52 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:56 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:48 #, elixir-autogen, elixir-format msgid "If you enabled optimization during compilation, select yes." @@ -1510,7 +1510,7 @@ msgid "Loading chart..." msgstr "" #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:77 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:105 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:109 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:35 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:99 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:49 @@ -1649,7 +1649,7 @@ msgstr "" msgid "Must be set to:" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:18 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:22 #, elixir-autogen, elixir-format msgid "Must match the name specified in the code. For example, in contract MyContract {..} MyContract is the contract name." msgstr "" @@ -1733,7 +1733,8 @@ msgstr "" #: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:9 #: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:9 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:42 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:9 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:46 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:38 #, elixir-autogen, elixir-format msgid "No" @@ -1802,7 +1803,7 @@ msgid "Optimization enabled" msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:70 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:58 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:62 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:54 #, elixir-autogen, elixir-format msgid "Optimization runs" @@ -1825,7 +1826,7 @@ msgstr "" msgid "Owner Address" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:73 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:77 #, elixir-autogen, elixir-format msgid "POA solidity flattener or the" msgstr "" @@ -2041,7 +2042,7 @@ msgstr "" msgid "Request to edit a public tag/label" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:108 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:112 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:38 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:104 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:52 @@ -2293,7 +2294,7 @@ msgstr "" msgid "The 0x library address. This can be found in the generated json file or Truffle output (if using truffle)." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:34 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:26 #, elixir-autogen, elixir-format msgid "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." @@ -2309,7 +2310,7 @@ msgstr "" msgid "The block height of a particular block is defined as the number of blocks preceding it in the blockchain." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:22 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:26 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:18 #, elixir-autogen, elixir-format msgid "The compiler version is specified in pragma solidity X.X.X. Use the compiler version rather than the nightly build. If using the Solidity compiler, run solc —version to check." @@ -2929,14 +2930,14 @@ msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:27 #: lib/block_scout_web/templates/address_contract/index.html.eex:29 -#: lib/block_scout_web/templates/address_contract/index.html.eex:161 -#: lib/block_scout_web/templates/address_contract/index.html.eex:192 +#: lib/block_scout_web/templates/address_contract/index.html.eex:163 +#: lib/block_scout_web/templates/address_contract/index.html.eex:194 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 #, elixir-autogen, elixir-format msgid "Verify & Publish" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:107 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:111 #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:37 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:103 #: lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex:51 @@ -3061,7 +3062,7 @@ msgstr "" msgid "Watch list" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:73 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:77 #, elixir-autogen, elixir-format msgid "We recommend using flattened code. This is necessary if your code utilizes a library or inherits dependencies. Use the" msgstr "" @@ -3092,7 +3093,8 @@ msgstr "" #: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:14 #: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:14 -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:47 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:14 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:51 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:43 #, elixir-autogen, elixir-format msgid "Yes" @@ -3249,7 +3251,7 @@ msgstr "" msgid "true" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:73 +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:77 #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" @@ -3424,3 +3426,23 @@ msgstr "" #, elixir-autogen, elixir-format, fuzzy msgid "Blocks With Internal Transactions Indexed" msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:72 +#, elixir-autogen, elixir-format, fuzzy +msgid "Drop all Solidity or Yul contract source files into the drop zone." +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:7 +#, elixir-autogen, elixir-format, fuzzy +msgid "New Solidity/Yul Smart Contract Verification" +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select Yes if you want to vefify Yul contract." +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63 +#, elixir-autogen, elixir-format, fuzzy +msgid "Sources *.sol or *.yul files" +msgstr "" diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index e1459101957c..3742f954c16f 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -197,11 +197,12 @@ defmodule Explorer.Chain.SmartContract do * `partially_verified` - whether contract verified using partial matched source code or not. * `is_vyper_contract` - boolean flag, determines if contract is Vyper or not * `file_path` - show the filename or path to the file of the contract source file - * `is_changed_bytecode` - boolean flag, determines if contract's bytecode was modified + * `is_changed_bytecode` - boolean flag, determines if contract's bytecode was modified * `bytecode_checked_at` - timestamp of the last check of contract's bytecode matching (DB and BlockChain) * `contract_code_md5` - md5(`t:Explorer.Chain.Address.t/0` `contract_code`) * `implementation_name` - name of the proxy implementation * `autodetect_constructor_args` - field was added for storing user's choice + * `is_yul` - field was added for storing user's choice """ @type t :: %Explorer.Chain.SmartContract{ @@ -221,7 +222,8 @@ defmodule Explorer.Chain.SmartContract do bytecode_checked_at: DateTime.t(), contract_code_md5: String.t(), implementation_name: String.t() | nil, - autodetect_constructor_args: boolean | nil + autodetect_constructor_args: boolean | nil, + is_yul: boolean | nil } schema "smart_contracts" do @@ -243,6 +245,7 @@ defmodule Explorer.Chain.SmartContract do field(:contract_code_md5, :string) field(:implementation_name, :string) field(:autodetect_constructor_args, :boolean, virtual: true) + field(:is_yul, :boolean, virtual: true) has_many( :decompiled_smart_contracts, @@ -291,7 +294,6 @@ defmodule Explorer.Chain.SmartContract do :compiler_version, :optimization, :contract_source_code, - :abi, :address_hash, :contract_code_md5 ]) @@ -431,6 +433,7 @@ defmodule Explorer.Chain.SmartContract do %__MODULE__{} |> changeset(Map.from_struct(twin_contract)) |> Changeset.put_change(:autodetect_constructor_args, true) + |> Changeset.put_change(:is_yul, false) |> Changeset.force_change(:address_hash, Changeset.get_field(changeset, :address_hash)) end @@ -443,6 +446,7 @@ defmodule Explorer.Chain.SmartContract do |> Changeset.put_change(:compiler_version, "latest") |> Changeset.put_change(:contract_source_code, "") |> Changeset.put_change(:autodetect_constructor_args, true) + |> Changeset.put_change(:is_yul, false) end def merge_twin_vyper_contract_with_changeset( diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex index e01e780f0482..d98d8537b5c0 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex @@ -51,7 +51,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do |> Map.put("external_libraries", contract_libraries) |> Map.put("name", contract_name) - publish_smart_contract(address_hash, prepared_params, Jason.decode!(abi_string)) + publish_smart_contract(address_hash, prepared_params, Jason.decode!(abi_string || "null")) {:ok, %{abi: abi, constructor_arguments: constructor_arguments}} -> params_with_constructor_arguments = @@ -245,7 +245,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do verified_via_sourcify: params["verified_via_sourcify"], partially_verified: params["partially_verified"], is_vyper_contract: false, - autodetect_constructor_args: params["autodetect_constructor_args"] + autodetect_constructor_args: params["autodetect_constructor_args"], + is_yul: params["is_yul"] || false } end diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex index bf8e9e6780f6..6e5c0e2919c9 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex @@ -51,7 +51,10 @@ defmodule Explorer.SmartContract.Solidity.Verifier do params |> Map.put("creation_bytecode", creation_tx_input) |> Map.put("deployed_bytecode", deployed_bytecode) - |> Map.put("sources", %{"#{params["name"]}.sol" => params["contract_source_code"]}) + |> Map.put("sources", %{ + "#{params["name"]}.#{smart_contract_source_file_extension(parse_boolean(params["is_yul"]))}" => + params["contract_source_code"] + }) |> Map.put("contract_libraries", params["external_libraries"]) |> Map.put("optimization_runs", prepare_optimization_runs(params["optimization"], params["optimization_runs"])) |> RustVerifierInterface.verify_multi_part() @@ -81,6 +84,9 @@ defmodule Explorer.SmartContract.Solidity.Verifier do end) end + defp smart_contract_source_file_extension(true), do: "yul" + defp smart_contract_source_file_extension(_), do: "sol" + defp prepare_optimization_runs(false_, _) when false_ in [false, "false"], do: nil defp prepare_optimization_runs(true_, runs) when true_ in [true, "true"] do diff --git a/apps/explorer/priv/repo/migrations/20221114113853_remove_not_null_constraint_from_abi.exs b/apps/explorer/priv/repo/migrations/20221114113853_remove_not_null_constraint_from_abi.exs new file mode 100644 index 000000000000..81903e79e30c --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20221114113853_remove_not_null_constraint_from_abi.exs @@ -0,0 +1,7 @@ +defmodule Explorer.Repo.Migrations.RemoveNotNullConstraintFromAbi do + use Ecto.Migration + + def change do + execute("ALTER TABLE smart_contracts ALTER COLUMN abi DROP NOT NULL;") + end +end From e569d83731957330a9ecd0af70bfe65720ad507f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Mon, 14 Nov 2022 20:09:07 +0300 Subject: [PATCH 05/66] Delete unused and stale contract-read-write.js import --- .../templates/address_write_contract/index.html.eex | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_write_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_write_contract/index.html.eex index 7febeee4a060..a1d915d2ec81 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_write_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_write_contract/index.html.eex @@ -53,5 +53,4 @@ <% end %>
-
From 9804a65ab71a4b3f40ad0cf6e48337c826e2d818 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Nov 2022 18:14:09 +0000 Subject: [PATCH 06/66] Bump chartjs-adapter-luxon in /apps/block_scout_web/assets Bumps [chartjs-adapter-luxon](https://github.com/chartjs/chartjs-adapter-luxon) from 1.2.0 to 1.2.1. - [Release notes](https://github.com/chartjs/chartjs-adapter-luxon/releases) - [Commits](https://github.com/chartjs/chartjs-adapter-luxon/compare/v1.2.0...v1.2.1) --- updated-dependencies: - dependency-name: chartjs-adapter-luxon dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 16 ++++++++-------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 4865bf888711..ec2fdb11e1d0 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -14,7 +14,7 @@ "bignumber.js": "^9.1.0", "bootstrap": "^4.6.0", "chart.js": "^3.9.1", - "chartjs-adapter-luxon": "^1.2.0", + "chartjs-adapter-luxon": "^1.2.1", "clipboard": "^2.0.11", "core-js": "^3.26.1", "crypto-browserify": "^3.12.0", @@ -5372,11 +5372,11 @@ "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" }, "node_modules/chartjs-adapter-luxon": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.2.0.tgz", - "integrity": "sha512-h1lEns7+8cUN/Dmk24dhrT9hpAimKImQxzHpILqXn2kocdzj9b/fDlBa8v8/OMq5rq0uZEx/NV1WpByH4l2/Rw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.2.1.tgz", + "integrity": "sha512-vECUr3m4IqjNyY8LZl6lbdKHmMW6+IBrn1QcaJHuuWca495y/i8N+exteYMXJktIEy8LZixwupcY3wpa315S4A==", "peerDependencies": { - "chart.js": "^3.0.0", + "chart.js": ">=3.0.0", "luxon": ">=1.0.0" } }, @@ -22436,9 +22436,9 @@ "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" }, "chartjs-adapter-luxon": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.2.0.tgz", - "integrity": "sha512-h1lEns7+8cUN/Dmk24dhrT9hpAimKImQxzHpILqXn2kocdzj9b/fDlBa8v8/OMq5rq0uZEx/NV1WpByH4l2/Rw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.2.1.tgz", + "integrity": "sha512-vECUr3m4IqjNyY8LZl6lbdKHmMW6+IBrn1QcaJHuuWca495y/i8N+exteYMXJktIEy8LZixwupcY3wpa315S4A==", "requires": {} }, "check-error": { diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index ba66fb8d6c5c..749cad69ba18 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -26,7 +26,7 @@ "bignumber.js": "^9.1.0", "bootstrap": "^4.6.0", "chart.js": "^3.9.1", - "chartjs-adapter-luxon": "^1.2.0", + "chartjs-adapter-luxon": "^1.2.1", "clipboard": "^2.0.11", "core-js": "^3.26.1", "crypto-browserify": "^3.12.0", From af8ca29309de8dbfb5232f07829c023a6a4252da Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Nov 2022 18:19:20 +0000 Subject: [PATCH 07/66] Bump sweetalert2 from 11.6.8 to 11.6.9 in /apps/block_scout_web/assets Bumps [sweetalert2](https://github.com/sweetalert2/sweetalert2) from 11.6.8 to 11.6.9. - [Release notes](https://github.com/sweetalert2/sweetalert2/releases) - [Changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md) - [Commits](https://github.com/sweetalert2/sweetalert2/compare/v11.6.8...v11.6.9) --- updated-dependencies: - dependency-name: sweetalert2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index ec2fdb11e1d0..3847ad618174 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -57,7 +57,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.8", + "sweetalert2": "^11.6.9", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", @@ -16776,9 +16776,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/sweetalert2": { - "version": "11.6.8", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.8.tgz", - "integrity": "sha512-0YHMaqF3DC67EI9uZzHpbU34rQV3acEFlnUCYmDSDNkeNOSFtSlF4DbWilfln+iUYv9s9aqbREXmKZRJqh5G5w==", + "version": "11.6.9", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.9.tgz", + "integrity": "sha512-zx0vdToB2Ququk+0qbXruca5KJuScyno77cqPfuwSiRwlMS5CwwnZDWiLqcRlIAZzDEbZHz9g/T7BDqAGqsQlA==", "funding": { "type": "individual", "url": "https://github.com/sponsors/limonte" @@ -31173,9 +31173,9 @@ } }, "sweetalert2": { - "version": "11.6.8", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.8.tgz", - "integrity": "sha512-0YHMaqF3DC67EI9uZzHpbU34rQV3acEFlnUCYmDSDNkeNOSFtSlF4DbWilfln+iUYv9s9aqbREXmKZRJqh5G5w==" + "version": "11.6.9", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.9.tgz", + "integrity": "sha512-zx0vdToB2Ququk+0qbXruca5KJuScyno77cqPfuwSiRwlMS5CwwnZDWiLqcRlIAZzDEbZHz9g/T7BDqAGqsQlA==" }, "symbol-tree": { "version": "3.2.4", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 749cad69ba18..ce04318e52cf 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -69,7 +69,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.8", + "sweetalert2": "^11.6.9", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", From 8c311e8b78c57fa49ebd288f47a4a698a6dc22a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Nov 2022 18:19:58 +0000 Subject: [PATCH 08/66] Bump chart.js from 3.9.1 to 4.0.1 in /apps/block_scout_web/assets Bumps [chart.js](https://github.com/chartjs/Chart.js) from 3.9.1 to 4.0.1. - [Release notes](https://github.com/chartjs/Chart.js/releases) - [Commits](https://github.com/chartjs/Chart.js/compare/v3.9.1...v4.0.1) --- updated-dependencies: - dependency-name: chart.js dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 17 ++++++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index ec2fdb11e1d0..68899fad33a8 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -13,7 +13,7 @@ "assert": "^2.0.0", "bignumber.js": "^9.1.0", "bootstrap": "^4.6.0", - "chart.js": "^3.9.1", + "chart.js": "^4.0.1", "chartjs-adapter-luxon": "^1.2.1", "clipboard": "^2.0.11", "core-js": "^3.26.1", @@ -5367,9 +5367,12 @@ } }, "node_modules/chart.js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", - "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.0.1.tgz", + "integrity": "sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==", + "engines": { + "pnpm": "^7.0.0" + } }, "node_modules/chartjs-adapter-luxon": { "version": "1.2.1", @@ -22431,9 +22434,9 @@ "dev": true }, "chart.js": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz", - "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.0.1.tgz", + "integrity": "sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==" }, "chartjs-adapter-luxon": { "version": "1.2.1", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 749cad69ba18..0a7563d8cddd 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -25,7 +25,7 @@ "assert": "^2.0.0", "bignumber.js": "^9.1.0", "bootstrap": "^4.6.0", - "chart.js": "^3.9.1", + "chart.js": "^4.0.1", "chartjs-adapter-luxon": "^1.2.1", "clipboard": "^2.0.11", "core-js": "^3.26.1", From cc2a075519bea6a39a33e5b175317eb12e24b9de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Nov 2022 18:20:26 +0000 Subject: [PATCH 09/66] Bump mini-css-extract-plugin in /apps/block_scout_web/assets Bumps [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/webpack-contrib/mini-css-extract-plugin/releases) - [Changelog](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v2.6.1...v2.7.0) --- updated-dependencies: - dependency-name: mini-css-extract-plugin dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index ec2fdb11e1d0..7fc211cbeb0b 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -81,7 +81,7 @@ "file-loader": "^6.2.0", "jest": "^29.3.1", "jest-environment-jsdom": "^29.3.1", - "mini-css-extract-plugin": "^2.6.1", + "mini-css-extract-plugin": "^2.7.0", "postcss": "^8.4.19", "postcss-loader": "^7.0.1", "sass": "^1.56.1", @@ -12895,9 +12895,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", + "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", "dev": true, "dependencies": { "schema-utils": "^4.0.0" @@ -28282,9 +28282,9 @@ "peer": true }, "mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", + "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", "dev": true, "requires": { "schema-utils": "^4.0.0" diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 749cad69ba18..7aca659a573c 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -93,7 +93,7 @@ "file-loader": "^6.2.0", "jest": "^29.3.1", "jest-environment-jsdom": "^29.3.1", - "mini-css-extract-plugin": "^2.6.1", + "mini-css-extract-plugin": "^2.7.0", "postcss": "^8.4.19", "postcss-loader": "^7.0.1", "sass": "^1.56.1", From 58d3a17af74b35b8e279a448b2b1ef96129b8bd0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Nov 2022 18:21:03 +0000 Subject: [PATCH 10/66] Bump webpack-cli from 4.10.0 to 5.0.0 in /apps/block_scout_web/assets Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.10.0 to 5.0.0. - [Release notes](https://github.com/webpack/webpack-cli/releases) - [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.10.0...webpack-cli@5.0.0) --- updated-dependencies: - dependency-name: webpack-cli dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 156 ++++++++++-------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 90 insertions(+), 68 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index ec2fdb11e1d0..d09d63f6eb6f 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -88,7 +88,7 @@ "sass-loader": "^13.2.0", "style-loader": "^3.3.1", "webpack": "^5.75.0", - "webpack-cli": "^4.10.0" + "webpack-cli": "^5.0.0" }, "engines": { "node": "16.x", @@ -3938,34 +3938,42 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.0.tgz", + "integrity": "sha512-war4OU8NGjBqU3DP3bx6ciODXIh7dSXcpQq+P4K2Tqyd8L5OjZ7COx9QXx/QdCIwL2qoX09Wr4Cwf7uS4qdEng==", "dev": true, + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.0.tgz", + "integrity": "sha512-NNxDgbo4VOkNhOlTgY0Elhz3vKpOJq4/PKeKg7r8cmYM+GQA9vDofLYyup8jS6EpUvhNmR30cHTCEIyvXpskwA==", "dev": true, - "dependencies": { - "envinfo": "^7.7.3" + "engines": { + "node": ">=14.15.0" }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.0.tgz", + "integrity": "sha512-Rumq5mHvGXamnOh3O8yLk1sjx8dB30qF1OeR6VC00DIR6SLJ4bwwUGKC4pE7qBFoQyyh0H9sAg3fikYgAqVR0w==", "dev": true, + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -9693,12 +9701,12 @@ } }, "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/ip": { @@ -15245,15 +15253,15 @@ } }, "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, "dependencies": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/redent": { @@ -17973,44 +17981,42 @@ } }, "node_modules/webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.0.tgz", + "integrity": "sha512-AACDTo20yG+xn6HPW5xjbn2Be4KUzQPebWXsDMHwPPyKh9OnTOJgZN2Nc+g/FZKV3ObRTYsGvibAvc+5jAUrVA==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", + "@webpack-cli/configtest": "^2.0.0", + "@webpack-cli/info": "^2.0.0", + "@webpack-cli/serve": "^2.0.0", "colorette": "^2.0.14", - "commander": "^7.0.0", + "commander": "^9.4.1", "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x" + "webpack": "5.x.x" }, "peerDependenciesMeta": { "@webpack-cli/generators": { "optional": true }, - "@webpack-cli/migrate": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -18019,6 +18025,15 @@ } } }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/webpack-merge": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", @@ -21339,25 +21354,23 @@ } }, "@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.0.tgz", + "integrity": "sha512-war4OU8NGjBqU3DP3bx6ciODXIh7dSXcpQq+P4K2Tqyd8L5OjZ7COx9QXx/QdCIwL2qoX09Wr4Cwf7uS4qdEng==", "dev": true, "requires": {} }, "@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.0.tgz", + "integrity": "sha512-NNxDgbo4VOkNhOlTgY0Elhz3vKpOJq4/PKeKg7r8cmYM+GQA9vDofLYyup8jS6EpUvhNmR30cHTCEIyvXpskwA==", "dev": true, - "requires": { - "envinfo": "^7.7.3" - } + "requires": {} }, "@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.0.tgz", + "integrity": "sha512-Rumq5mHvGXamnOh3O8yLk1sjx8dB30qF1OeR6VC00DIR6SLJ4bwwUGKC4pE7qBFoQyyh0H9sAg3fikYgAqVR0w==", "dev": true, "requires": {} }, @@ -25822,9 +25835,9 @@ } }, "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true }, "ip": { @@ -30009,12 +30022,12 @@ } }, "rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, "requires": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" } }, "redent": { @@ -32175,23 +32188,32 @@ } }, "webpack-cli": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", - "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.0.tgz", + "integrity": "sha512-AACDTo20yG+xn6HPW5xjbn2Be4KUzQPebWXsDMHwPPyKh9OnTOJgZN2Nc+g/FZKV3ObRTYsGvibAvc+5jAUrVA==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", + "@webpack-cli/configtest": "^2.0.0", + "@webpack-cli/info": "^2.0.0", + "@webpack-cli/serve": "^2.0.0", "colorette": "^2.0.14", - "commander": "^7.0.0", + "commander": "^9.4.1", "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true + } } }, "webpack-merge": { diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 749cad69ba18..ffba73b2b5a3 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -100,7 +100,7 @@ "sass-loader": "^13.2.0", "style-loader": "^3.3.1", "webpack": "^5.75.0", - "webpack-cli": "^4.10.0" + "webpack-cli": "^5.0.0" }, "jest": { "moduleNameMapper": { From 9f44056841890b43167b6202dce14223d8684613 Mon Sep 17 00:00:00 2001 From: sl1depengwyn Date: Fri, 18 Nov 2022 14:56:07 +0300 Subject: [PATCH 11/66] Fix token name with unicode graphemes shortening --- CHANGELOG.md | 1 + .../lib/explorer/token/metadata_retriever.ex | 5 +- .../token/metadata_retriever_test.exs | 52 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01551628f4c0..bf5df91646a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ ### Fixes +- [#6475](https://github.com/blockscout/blockscout/pull/6475) - Fix token name with unicode graphemes shortening - [#6420](https://github.com/blockscout/blockscout/pull/6420) - Fix address logs search - [#6390](https://github.com/blockscout/blockscout/pull/6390) - Fix transactions responses in API v2 - [#6357](https://github.com/blockscout/blockscout/pull/6357), [#6409](https://github.com/blockscout/blockscout/pull/6409), [#6428](https://github.com/blockscout/blockscout/pull/6428) - Fix definitions of NETWORK_PATH, API_PATH, SOCKET_ROOT: process trailing slash diff --git a/apps/explorer/lib/explorer/token/metadata_retriever.ex b/apps/explorer/lib/explorer/token/metadata_retriever.ex index 304b9330b68d..29b744d708a0 100644 --- a/apps/explorer/lib/explorer/token/metadata_retriever.ex +++ b/apps/explorer/lib/explorer/token/metadata_retriever.ex @@ -342,7 +342,10 @@ defmodule Explorer.Token.MetadataRetriever do defp handle_large_string(nil), do: nil defp handle_large_string(string), do: handle_large_string(string, byte_size(string)) - defp handle_large_string(string, size) when size > 255, do: binary_part(string, 0, 255) + + defp handle_large_string(string, size) when size > 255, + do: string |> binary_part(0, 255) |> String.chunk(:valid) |> List.first() + defp handle_large_string(string, _size), do: string defp remove_null_bytes(string) do diff --git a/apps/explorer/test/explorer/token/metadata_retriever_test.exs b/apps/explorer/test/explorer/token/metadata_retriever_test.exs index 9f8ead7468d8..404ae713bb9f 100644 --- a/apps/explorer/test/explorer/token/metadata_retriever_test.exs +++ b/apps/explorer/test/explorer/token/metadata_retriever_test.exs @@ -340,6 +340,58 @@ defmodule Explorer.Token.MetadataRetrieverTest do assert MetadataRetriever.get_functions_of(token.contract_address_hash) == expected end + test "shortens strings larger than 255 characters with unicode graphemes" do + long_token_name_shortened = + "文章の論旨や要点を短くまとめて表現する要約文。学生の頃、レポート作成などで書いた経験があるものの、それ以降はまったく書いていないという人は多いことでしょう。 しかし、文章" + + token = insert(:token, contract_address: build(:contract_address)) + + expect( + EthereumJSONRPC.Mox, + :json_rpc, + 1, + fn requests, _opts -> + {:ok, + Enum.map(requests, fn + %{id: id, method: "eth_call", params: [%{data: "0x313ce567", to: _}, "latest"]} -> + %{ + id: id, + result: "0x0000000000000000000000000000000000000000000000000000000000000012" + } + + %{id: id, method: "eth_call", params: [%{data: "0x06fdde03", to: _}, "latest"]} -> + %{ + id: id, + result: + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000128e69687e7aba0e381aee8ab96e697a8e38284e8a681e782b9e38292e79fade3818fe381bee381a8e38281e381a6e8a1a8e78fbee38199e3828be8a681e7b484e69687e38082e5ada6e7949fe381aee9a083e38081e383ace3839de383bce38388e4bd9ce68890e381aae381a9e381a7e69bb8e38184e3819fe7b58ce9a893e3818ce38182e3828be38282e381aee381aee38081e3819de3828ce4bba5e9998de381afe381bee381a3e3819fe3818fe69bb8e38184e381a6e38184e381aae38184e381a8e38184e38186e4babae381afe5a49ae38184e38193e381a8e381a7e38197e38287e38186e380822020e38197e3818be38197e38081e69687e7aba0e4bd9ce68890e3818ce88ba6e6898be381aae4babae38284e38081e69687e7aba0e3818ce3828fe3818b000000000000000000000000000000000000000000000000" + } + + %{id: id, method: "eth_call", params: [%{data: "0x95d89b41", to: _}, "latest"]} -> + %{ + id: id, + result: + "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003424e540000000000000000000000000000000000000000000000000000000000" + } + + %{id: id, method: "eth_call", params: [%{data: "0x18160ddd", to: _}, "latest"]} -> + %{ + id: id, + result: "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000" + } + end)} + end + ) + + expected = %{ + name: long_token_name_shortened, + decimals: 18, + total_supply: 1_000_000_000_000_000_000, + symbol: "BNT" + } + + assert MetadataRetriever.get_functions_of(token.contract_address_hash) == expected + end + test "retries when some function gave error" do token = insert(:token, contract_address: build(:contract_address)) From 02e57f13f0bc70ef9954f69db51acb8e9f129570 Mon Sep 17 00:00:00 2001 From: Qwerty5Uiop Date: Fri, 18 Nov 2022 16:13:03 +0400 Subject: [PATCH 12/66] Replace token balances multiple token_id indexes to a single one --- ..._modify_address_token_balances_indexes.exs | 58 +++++++++++++++++++ ...address_current_token_balances_indexes.exs | 31 ++++++++++ 2 files changed, 89 insertions(+) create mode 100644 apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs create mode 100644 apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs diff --git a/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs b/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs new file mode 100644 index 000000000000..3d7c4da63ce6 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs @@ -0,0 +1,58 @@ +defmodule Explorer.Repo.Migrations.ModifyAddressTokenBalancesIndexes do + use Ecto.Migration + + def change do + drop_if_exists( + unique_index( + :address_token_balances, + ~w(address_hash token_contract_address_hash block_number)a, + name: :fetched_token_balances, + where: "token_id IS NULL" + ) + ) + + drop_if_exists( + unique_index( + :address_token_balances, + ~w(address_hash token_contract_address_hash token_id block_number)a, + name: :fetched_token_balances_with_token_id, + where: "token_id IS NOT NULL" + ) + ) + + create_if_not_exists( + unique_index( + :address_token_balances, + [:address_hash, :token_contract_address_hash, "COALESCE(token_id, 0)", :block_number], + name: :fetched_token_balances + ) + ) + + drop_if_exists( + unique_index( + :address_token_balances, + ~w(address_hash token_contract_address_hash block_number)a, + name: :unfetched_token_balances, + where: "value_fetched_at IS NULL and token_id IS NULL" + ) + ) + + drop_if_exists( + unique_index( + :address_token_balances, + ~w(address_hash token_contract_address_hash token_id block_number)a, + name: :unfetched_token_balances_with_token_id, + where: "value_fetched_at IS NULL and token_id IS NOT NULL" + ) + ) + + create_if_not_exists( + unique_index( + :address_token_balances, + [:address_hash, :token_contract_address_hash, "COALESCE(token_id, 0)", :block_number], + name: :unfetched_token_balances, + where: "value_fetched_at IS NULL" + ) + ) + end +end diff --git a/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs b/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs new file mode 100644 index 000000000000..31554d88d3d1 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs @@ -0,0 +1,31 @@ +defmodule Explorer.Repo.Migrations.ModifyAddressCurrentTokenBalancesIndexes do + use Ecto.Migration + + def change do + drop_if_exists( + unique_index( + :address_current_token_balances, + ~w(address_hash token_contract_address_hash)a, + name: :fetched_current_token_balances, + where: "token_id IS NULL" + ) + ) + + drop_if_exists( + unique_index( + :address_current_token_balances, + ~w(address_hash token_contract_address_hash token_id)a, + name: :fetched_current_token_balances_with_token_id, + where: "token_id IS NOT NULL" + ) + ) + + create_if_not_exists( + unique_index( + :address_current_token_balances, + [:address_hash, :token_contract_address_hash, "COALESCE(token_id, 0)"], + name: :fetched_current_token_balances + ) + ) + end +end From dfcdb171474881b211158fbd907e1b343342f9a9 Mon Sep 17 00:00:00 2001 From: Qwerty5Uiop Date: Fri, 18 Nov 2022 16:15:36 +0400 Subject: [PATCH 13/66] Update token balances import in order to new indexes --- CHANGELOG.md | 1 + .../runner/address/current_token_balances.ex | 84 ++++------------- .../import/runner/address/token_balances.ex | 90 +++---------------- .../address/current_token_balances_test.exs | 26 +++--- .../runner/address/token_balances_test.exs | 66 ++++++++++++++ 5 files changed, 110 insertions(+), 157 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01551628f4c0..95b15c7b3712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [#6443](https://github.com/blockscout/blockscout/pull/6443) - Drop internal transactions order index - [#6450](https://github.com/blockscout/blockscout/pull/6450) - INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE and INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY env variables - [#6454](https://github.com/blockscout/blockscout/pull/6454) - INDEXER_RECEIPTS_BATCH_SIZE, INDEXER_RECEIPTS_CONCURRENCY, INDEXER_COIN_BALANCES_BATCH_SIZE, INDEXER_COIN_BALANCES_CONCURRENCY env variables +- [#6476](https://github.com/blockscout/blockscout/pull/6476) - Update token balances indexes ### Fixes diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex b/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex index 4e225dcc29d7..85284dafc42c 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex @@ -242,51 +242,15 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalances do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # Enforce CurrentTokenBalance ShareLocks order (see docs: sharelocks.md) - %{ - changes_list_no_token_id: changes_list_no_token_id, - changes_list_with_token_id: changes_list_with_token_id - } = + ordered_changes_list = changes_list - |> Enum.reduce(%{changes_list_no_token_id: [], changes_list_with_token_id: []}, fn change, acc -> - updated_change = - if Map.has_key?(change, :token_id) and Map.get(change, :token_type) == "ERC-1155" do - change - else - Map.put(change, :token_id, nil) - end - - if updated_change.token_id do - changes_list_with_token_id = [updated_change | acc.changes_list_with_token_id] - - %{ - changes_list_no_token_id: acc.changes_list_no_token_id, - changes_list_with_token_id: changes_list_with_token_id - } + |> Enum.map(fn change -> + if Map.has_key?(change, :token_id) and Map.get(change, :token_type) == "ERC-1155" do + change else - changes_list_no_token_id = [updated_change | acc.changes_list_no_token_id] - - %{ - changes_list_no_token_id: changes_list_no_token_id, - changes_list_with_token_id: acc.changes_list_with_token_id - } + Map.put(change, :token_id, nil) end end) - - ordered_changes_list_no_token_id = - changes_list_no_token_id - |> Enum.group_by(fn %{ - address_hash: address_hash, - token_contract_address_hash: token_contract_address_hash - } -> - {address_hash, token_contract_address_hash} - end) - |> Enum.map(fn {_, grouped_address_token_balances} -> - Enum.max_by(grouped_address_token_balances, fn %{block_number: block_number} -> block_number end) - end) - |> Enum.sort_by(&{&1.token_contract_address_hash, &1.address_hash}) - - ordered_changes_list_with_token_id = - changes_list_with_token_id |> Enum.group_by(fn %{ address_hash: address_hash, token_contract_address_hash: token_contract_address_hash, @@ -295,33 +259,18 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalances do {address_hash, token_contract_address_hash, token_id} end) |> Enum.map(fn {_, grouped_address_token_balances} -> - Enum.max_by(grouped_address_token_balances, fn %{block_number: block_number} -> block_number end) + Enum.max_by(grouped_address_token_balances, fn balance -> + {Map.get(balance, :block_number), Map.get(balance, :value_fetched_at)} + end) end) |> Enum.sort_by(&{&1.token_contract_address_hash, &1.token_id, &1.address_hash}) - {:ok, inserted_changes_list_no_token_id} = - if Enum.count(ordered_changes_list_no_token_id) > 0 do - Import.insert_changes_list( - repo, - ordered_changes_list_no_token_id, - conflict_target: {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash) WHERE token_id IS NULL>}, - on_conflict: on_conflict, - for: CurrentTokenBalance, - returning: true, - timeout: timeout, - timestamps: timestamps - ) - else - {:ok, []} - end - - {:ok, inserted_changes_list_with_token_id} = - if Enum.count(ordered_changes_list_with_token_id) > 0 do + {:ok, inserted_changes_list} = + if Enum.count(ordered_changes_list) > 0 do Import.insert_changes_list( repo, - ordered_changes_list_with_token_id, - conflict_target: - {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, token_id) WHERE token_id IS NOT NULL>}, + ordered_changes_list, + conflict_target: {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, COALESCE(token_id, 0))>}, on_conflict: on_conflict, for: CurrentTokenBalance, returning: true, @@ -332,7 +281,7 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalances do {:ok, []} end - inserted_changes_list_no_token_id ++ inserted_changes_list_with_token_id + inserted_changes_list end defp default_on_conflict do @@ -351,9 +300,10 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalances do ], where: fragment("? < EXCLUDED.block_number", current_token_balance.block_number) or - (fragment("EXCLUDED.value IS NOT NULL") and - is_nil(current_token_balance.value_fetched_at) and - fragment("? = EXCLUDED.block_number", current_token_balance.block_number)) + (fragment("? = EXCLUDED.block_number", current_token_balance.block_number) and + fragment("EXCLUDED.value IS NOT NULL") and + (is_nil(current_token_balance.value_fetched_at) or + fragment("? < EXCLUDED.value_fetched_at", current_token_balance.value_fetched_at))) ) end diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex b/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex index e8fc2d33b1e0..efc3b97a9b7d 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex @@ -66,58 +66,15 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalances do on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0) # Enforce TokenBalance ShareLocks order (see docs: sharelocks.md) - %{ - changes_list_no_token_id: changes_list_no_token_id, - changes_list_with_token_id: changes_list_with_token_id - } = + ordered_changes_list = changes_list - |> Enum.reduce(%{changes_list_no_token_id: [], changes_list_with_token_id: []}, fn change, acc -> - updated_change = - if Map.has_key?(change, :token_id) and Map.get(change, :token_type) == "ERC-1155" do - change - else - Map.put(change, :token_id, nil) - end - - if updated_change.token_id do - changes_list_with_token_id = [updated_change | acc.changes_list_with_token_id] - - %{ - changes_list_no_token_id: acc.changes_list_no_token_id, - changes_list_with_token_id: changes_list_with_token_id - } + |> Enum.map(fn change -> + if Map.has_key?(change, :token_id) and Map.get(change, :token_type) == "ERC-1155" do + change else - changes_list_no_token_id = [updated_change | acc.changes_list_no_token_id] - - %{ - changes_list_no_token_id: changes_list_no_token_id, - changes_list_with_token_id: acc.changes_list_with_token_id - } + Map.put(change, :token_id, nil) end end) - - ordered_changes_list_no_token_id = - changes_list_no_token_id - |> Enum.group_by(fn %{ - address_hash: address_hash, - token_contract_address_hash: token_contract_address_hash, - block_number: block_number - } -> - {token_contract_address_hash, address_hash, block_number} - end) - |> Enum.map(fn {_, grouped_address_token_balances} -> - dedup = Enum.dedup(grouped_address_token_balances) - - if Enum.count(dedup) > 1 do - Enum.max_by(dedup, fn %{value_fetched_at: value_fetched_at} -> value_fetched_at end) - else - Enum.at(dedup, 0) - end - end) - |> Enum.sort_by(&{&1.token_contract_address_hash, &1.address_hash, &1.block_number}) - - ordered_changes_list_with_token_id = - changes_list_with_token_id |> Enum.group_by(fn %{ address_hash: address_hash, token_contract_address_hash: token_contract_address_hash, @@ -128,20 +85,20 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalances do end) |> Enum.map(fn {_, grouped_address_token_balances} -> if Enum.count(grouped_address_token_balances) > 1 do - Enum.max_by(grouped_address_token_balances, fn %{value_fetched_at: value_fetched_at} -> value_fetched_at end) + Enum.max_by(grouped_address_token_balances, fn balance -> Map.get(balance, :value_fetched_at) end) else Enum.at(grouped_address_token_balances, 0) end end) |> Enum.sort_by(&{&1.token_contract_address_hash, &1.token_id, &1.address_hash, &1.block_number}) - {:ok, inserted_changes_list_no_token_id} = - if Enum.count(ordered_changes_list_no_token_id) > 0 do + {:ok, inserted_changes_list} = + if Enum.count(ordered_changes_list) > 0 do Import.insert_changes_list( repo, - ordered_changes_list_no_token_id, + ordered_changes_list, conflict_target: - {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, block_number) WHERE token_id IS NULL>}, + {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, COALESCE(token_id, 0), block_number)>}, on_conflict: on_conflict, for: TokenBalance, returning: true, @@ -152,26 +109,6 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalances do {:ok, []} end - {:ok, inserted_changes_list_with_token_id} = - if Enum.count(ordered_changes_list_with_token_id) > 0 do - Import.insert_changes_list( - repo, - ordered_changes_list_with_token_id, - conflict_target: - {:unsafe_fragment, - ~s<(address_hash, token_contract_address_hash, token_id, block_number) WHERE token_id IS NOT NULL>}, - on_conflict: on_conflict, - for: TokenBalance, - returning: true, - timeout: timeout, - timestamps: timestamps - ) - else - {:ok, []} - end - - inserted_changes_list = inserted_changes_list_no_token_id ++ inserted_changes_list_with_token_id - {:ok, inserted_changes_list} end @@ -180,7 +117,7 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalances do token_balance in TokenBalance, update: [ set: [ - value: fragment("EXCLUDED.value"), + value: fragment("COALESCE(EXCLUDED.value, ?)", token_balance.value), value_fetched_at: fragment("EXCLUDED.value_fetched_at"), token_type: fragment("EXCLUDED.token_type"), inserted_at: fragment("LEAST(EXCLUDED.inserted_at, ?)", token_balance.inserted_at), @@ -188,9 +125,8 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalances do ] ], where: - fragment("EXCLUDED.value IS NOT NULL") and - (is_nil(token_balance.value_fetched_at) or - fragment("? < EXCLUDED.value_fetched_at", token_balance.value_fetched_at)) + is_nil(token_balance.value_fetched_at) or fragment("EXCLUDED.value_fetched_at IS NULL") or + fragment("? < EXCLUDED.value_fetched_at", token_balance.value_fetched_at) ) end end diff --git a/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs b/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs index 7c34c72719cd..31eba0553de0 100644 --- a/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs @@ -97,30 +97,30 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalancesTest do %Explorer.Chain.Address.CurrentTokenBalance{ address_hash: ^address_hash, block_number: ^block_number, - token_contract_address_hash: ^token_erc_20_contract_address_hash, - value: ^value_3, - token_id: ^token_id_3 + token_contract_address_hash: ^token_contract_address_hash, + value: ^value_1, + token_id: ^token_id_1 }, %Explorer.Chain.Address.CurrentTokenBalance{ address_hash: ^address_hash, block_number: ^block_number, - token_contract_address_hash: ^token_erc_721_contract_address_hash, - value: ^value_5, - token_id: nil + token_contract_address_hash: ^token_contract_address_hash, + value: ^value_2, + token_id: ^token_id_2 }, %Explorer.Chain.Address.CurrentTokenBalance{ address_hash: ^address_hash, block_number: ^block_number, - token_contract_address_hash: ^token_contract_address_hash, - value: ^value_1, - token_id: ^token_id_1 + token_contract_address_hash: ^token_erc_20_contract_address_hash, + value: ^value_3, + token_id: ^token_id_3 }, %Explorer.Chain.Address.CurrentTokenBalance{ address_hash: ^address_hash, block_number: ^block_number, - token_contract_address_hash: ^token_contract_address_hash, - value: ^value_2, - token_id: ^token_id_2 + token_contract_address_hash: ^token_erc_721_contract_address_hash, + value: ^value_5, + token_id: nil } ], address_current_token_balances_update_token_holder_counts: [ @@ -172,7 +172,7 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalancesTest do block_number: block_number, token_contract_address_hash: token_erc_721.contract_address_hash, value: value_4, - value_fetched_at: DateTime.utc_now(), + value_fetched_at: DateTime.add(DateTime.utc_now(), -1), token_id: token_id_4, token_type: "ERC-721" }, diff --git a/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs b/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs index f44b6bca792f..15725869bd85 100644 --- a/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs +++ b/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs @@ -41,6 +41,7 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalancesTest do address_hash: ^address_hash, block_number: ^block_number, token_contract_address_hash: ^token_contract_address_hash, + token_id: nil, value: ^value, value_fetched_at: ^value_fetched_at } @@ -83,6 +84,7 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalancesTest do address_hash: address_hash, block_number: ^block_number, token_contract_address_hash: ^token_contract_address_hash, + token_id: nil, value: nil, value_fetched_at: ^value_fetched_at } @@ -153,6 +155,70 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalancesTest do run_changes(new_changes, options) end + test "set value_fetched_at to null for existing record if incoming data has this field empty" do + address = insert(:address) + token = insert(:token) + + options = %{ + timeout: :infinity, + timestamps: %{inserted_at: DateTime.utc_now(), updated_at: DateTime.utc_now()} + } + + block_number = 1 + + value = Decimal.new(100) + value_fetched_at = DateTime.utc_now() + + token_contract_address_hash = token.contract_address_hash + address_hash = address.hash + + first_changes = %{ + address_hash: address_hash, + block_number: block_number, + token_contract_address_hash: token_contract_address_hash, + token_id: 11, + token_type: "ERC-721", + value: value, + value_fetched_at: value_fetched_at + } + + assert {:ok, + %{ + address_token_balances: [ + %TokenBalance{ + address_hash: address_hash, + block_number: ^block_number, + token_contract_address_hash: ^token_contract_address_hash, + token_id: nil, + value: ^value, + value_fetched_at: ^value_fetched_at + } + ] + }} = run_changes(first_changes, options) + + second_changes = %{ + address_hash: address_hash, + block_number: block_number, + token_contract_address_hash: token_contract_address_hash, + token_id: 12, + token_type: "ERC-721" + } + + assert {:ok, + %{ + address_token_balances: [ + %TokenBalance{ + address_hash: address_hash, + block_number: ^block_number, + token_contract_address_hash: ^token_contract_address_hash, + token_id: nil, + value: ^value, + value_fetched_at: nil + } + ] + }} = run_changes(second_changes, options) + end + defp run_changes(changes, options) when is_map(changes) do run_changes_list([changes], options) end From 11220edeba93445f62f12c36a1e9ee642db7773f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Fri, 18 Nov 2022 17:22:31 +0300 Subject: [PATCH 14/66] Add gettext --- .../_yul_contracts_switcher.html.eex | 2 +- apps/block_scout_web/priv/gettext/default.pot | 5 +++++ apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex index f7b212d4afb0..ce83d4d47e5d 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex @@ -1,6 +1,6 @@
- <%= label @f, "Is yul contract" %> + <%= label @f, :is_yul, gettext("Is Yul contract") %>
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index e28e09fdfcb7..091adcf203be 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -3446,3 +3446,8 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Sources *.sol or *.yul files" msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Is Yul contract" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 5b35d4bbe42b..577368b450ac 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -3446,3 +3446,8 @@ msgstr "" #, elixir-autogen, elixir-format, fuzzy msgid "Sources *.sol or *.yul files" msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Is Yul contract" +msgstr "" From f0e375b0ba0641c2fab4d9d2dbafa4eb77622e9e Mon Sep 17 00:00:00 2001 From: Qwerty5Uiop Date: Mon, 21 Nov 2022 19:40:08 +0400 Subject: [PATCH 15/66] Fix token balances migrations --- CHANGELOG.md | 2 +- .../chain/import/runner/address/current_token_balances.ex | 2 +- .../explorer/chain/import/runner/address/token_balances.ex | 2 +- .../20221117075456_modify_address_token_balances_indexes.exs | 4 ++-- ...17080657_modify_address_current_token_balances_indexes.exs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b3017feb69f..326765ebad1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ - [#6443](https://github.com/blockscout/blockscout/pull/6443) - Drop internal transactions order index - [#6450](https://github.com/blockscout/blockscout/pull/6450) - INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE and INDEXER_INTERNAL_TRANSACTIONS_CONCURRENCY env variables - [#6454](https://github.com/blockscout/blockscout/pull/6454) - INDEXER_RECEIPTS_BATCH_SIZE, INDEXER_RECEIPTS_CONCURRENCY, INDEXER_COIN_BALANCES_BATCH_SIZE, INDEXER_COIN_BALANCES_CONCURRENCY env variables -- [#6476](https://github.com/blockscout/blockscout/pull/6476) - Update token balances indexes +- [#6476](https://github.com/blockscout/blockscout/pull/6476), [#6484](https://github.com/blockscout/blockscout/pull/6484) - Update token balances indexes ### Fixes diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex b/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex index 85284dafc42c..4480cd883b01 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex @@ -270,7 +270,7 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalances do Import.insert_changes_list( repo, ordered_changes_list, - conflict_target: {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, COALESCE(token_id, 0))>}, + conflict_target: {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, COALESCE(token_id, -1))>}, on_conflict: on_conflict, for: CurrentTokenBalance, returning: true, diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex b/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex index efc3b97a9b7d..544e388074c5 100644 --- a/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex +++ b/apps/explorer/lib/explorer/chain/import/runner/address/token_balances.ex @@ -98,7 +98,7 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalances do repo, ordered_changes_list, conflict_target: - {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, COALESCE(token_id, 0), block_number)>}, + {:unsafe_fragment, ~s<(address_hash, token_contract_address_hash, COALESCE(token_id, -1), block_number)>}, on_conflict: on_conflict, for: TokenBalance, returning: true, diff --git a/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs b/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs index 3d7c4da63ce6..9c21c4b40a89 100644 --- a/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs +++ b/apps/explorer/priv/repo/migrations/20221117075456_modify_address_token_balances_indexes.exs @@ -23,7 +23,7 @@ defmodule Explorer.Repo.Migrations.ModifyAddressTokenBalancesIndexes do create_if_not_exists( unique_index( :address_token_balances, - [:address_hash, :token_contract_address_hash, "COALESCE(token_id, 0)", :block_number], + [:address_hash, :token_contract_address_hash, "COALESCE(token_id, -1)", :block_number], name: :fetched_token_balances ) ) @@ -49,7 +49,7 @@ defmodule Explorer.Repo.Migrations.ModifyAddressTokenBalancesIndexes do create_if_not_exists( unique_index( :address_token_balances, - [:address_hash, :token_contract_address_hash, "COALESCE(token_id, 0)", :block_number], + [:address_hash, :token_contract_address_hash, "COALESCE(token_id, -1)", :block_number], name: :unfetched_token_balances, where: "value_fetched_at IS NULL" ) diff --git a/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs b/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs index 31554d88d3d1..295a7a5c3f15 100644 --- a/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs +++ b/apps/explorer/priv/repo/migrations/20221117080657_modify_address_current_token_balances_indexes.exs @@ -23,7 +23,7 @@ defmodule Explorer.Repo.Migrations.ModifyAddressCurrentTokenBalancesIndexes do create_if_not_exists( unique_index( :address_current_token_balances, - [:address_hash, :token_contract_address_hash, "COALESCE(token_id, 0)"], + [:address_hash, :token_contract_address_hash, "COALESCE(token_id, -1)"], name: :fetched_current_token_balances ) ) From d501db5adeae817289b1c1b1c1bb6ea85bf789ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 19:03:40 +0000 Subject: [PATCH 16/66] Bump sweetalert2 from 11.6.9 to 11.6.10 in /apps/block_scout_web/assets Bumps [sweetalert2](https://github.com/sweetalert2/sweetalert2) from 11.6.9 to 11.6.10. - [Release notes](https://github.com/sweetalert2/sweetalert2/releases) - [Changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md) - [Commits](https://github.com/sweetalert2/sweetalert2/compare/v11.6.9...v11.6.10) --- updated-dependencies: - dependency-name: sweetalert2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 8144800d1cf8..20486b02770d 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -57,7 +57,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.9", + "sweetalert2": "^11.6.10", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", @@ -16787,9 +16787,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/sweetalert2": { - "version": "11.6.9", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.9.tgz", - "integrity": "sha512-zx0vdToB2Ququk+0qbXruca5KJuScyno77cqPfuwSiRwlMS5CwwnZDWiLqcRlIAZzDEbZHz9g/T7BDqAGqsQlA==", + "version": "11.6.10", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.10.tgz", + "integrity": "sha512-/tzEmEYqqHVkO6iMfvCFcmaO78un93CdZIhB+DGj9BLMkcuXS8jo2bmYoxjEAryhxsKPqXiWmZNo3gw/qw/ZwQ==", "funding": { "type": "individual", "url": "https://github.com/sponsors/limonte" @@ -31189,9 +31189,9 @@ } }, "sweetalert2": { - "version": "11.6.9", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.9.tgz", - "integrity": "sha512-zx0vdToB2Ququk+0qbXruca5KJuScyno77cqPfuwSiRwlMS5CwwnZDWiLqcRlIAZzDEbZHz9g/T7BDqAGqsQlA==" + "version": "11.6.10", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.10.tgz", + "integrity": "sha512-/tzEmEYqqHVkO6iMfvCFcmaO78un93CdZIhB+DGj9BLMkcuXS8jo2bmYoxjEAryhxsKPqXiWmZNo3gw/qw/ZwQ==" }, "symbol-tree": { "version": "3.2.4", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 92e1f2b6a294..63b28e6a480f 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -69,7 +69,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.9", + "sweetalert2": "^11.6.10", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", From 5b3a203f36dea657e3f588bd260af74ecd06721b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 19:04:32 +0000 Subject: [PATCH 17/66] Bump eslint from 8.27.0 to 8.28.0 in /apps/block_scout_web/assets Bumps [eslint](https://github.com/eslint/eslint) from 8.27.0 to 8.28.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.27.0...v8.28.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 8144800d1cf8..40240726eadb 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -73,7 +73,7 @@ "copy-webpack-plugin": "^11.0.0", "css-loader": "^5.2.7", "css-minimizer-webpack-plugin": "^4.2.2", - "eslint": "^8.27.0", + "eslint": "^8.28.0", "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-node": "^11.1.0", @@ -7030,9 +7030,9 @@ } }, "node_modules/eslint": { - "version": "8.27.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", - "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", + "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.3", @@ -23718,9 +23718,9 @@ } }, "eslint": { - "version": "8.27.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.27.0.tgz", - "integrity": "sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", + "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.3", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 92e1f2b6a294..ae0bc5df7350 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -85,7 +85,7 @@ "copy-webpack-plugin": "^11.0.0", "css-loader": "^5.2.7", "css-minimizer-webpack-plugin": "^4.2.2", - "eslint": "^8.27.0", + "eslint": "^8.28.0", "eslint-config-standard": "^17.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-node": "^11.1.0", From 1e1b29307aa136390a98ba658962e0873c3e1f30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Nov 2022 19:06:13 +0000 Subject: [PATCH 18/66] Bump ex_doc from 0.29.0 to 0.29.1 Bumps [ex_doc](https://github.com/elixir-lang/ex_doc) from 0.29.0 to 0.29.1. - [Release notes](https://github.com/elixir-lang/ex_doc/releases) - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md) - [Commits](https://github.com/elixir-lang/ex_doc/compare/v0.29.0...v0.29.1) --- updated-dependencies: - dependency-name: ex_doc dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index e7741d9471f4..5844b595f942 100644 --- a/mix.lock +++ b/mix.lock @@ -46,7 +46,7 @@ "ex_cldr_lists": {:hex, :ex_cldr_lists, "2.10.0", "4d4c9877da2d0417fd832907d69974e8328969f75fafc79b05ccf85f549f6281", [:mix], [{:ex_cldr_numbers, "~> 2.25", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "adc040cde7b97f7fd7c0b35dd69ddb6fcf607303ae6355bb1851deae1f8b0652"}, "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.28.0", "506f5d36a2b72a21bbcb6e55dfdc5c3ff7f1c07d65e516461125158d10661beb", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "83342ff668aedf3aa5c54b048ce1da0f91317b6596b14880a5f87d45cd1c49d2"}, "ex_cldr_units": {:hex, :ex_cldr_units, "3.15.0", "3a834dfaf4daa0723cac165d528eacdbc3f9daec580f817b2847007fe07afdca", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.28", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:ratio, "~> 2.4", [hex: :ratio, repo: "hexpm", optional: false]}], "hexpm", "bac7c3f6042482869dd67445adddaec2c263f561a8c2035eac7bd5f9d5ae1691"}, - "ex_doc": {:hex, :ex_doc, "0.29.0", "4a1cb903ce746aceef9c1f9ae8a6c12b742a5461e6959b9d3b24d813ffbea146", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "f096adb8bbca677d35d278223361c7792d496b3fc0d0224c9d4bc2f651af5db1"}, + "ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"}, "ex_json_schema": {:hex, :ex_json_schema, "0.9.2", "c9a42e04e70cd70eb11a8903a22e8ec344df16edef4cb8e6ec84ed0caffc9f0f", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "4854329cb352b6c01c4c4b8dbfb3be14dc5bea19ea13e0eafade4ff22ba55224"}, "ex_keccak": {:hex, :ex_keccak, "0.6.0", "0e1f8974dd6630dd4fb0b64f9eabbceeffb9675da3ab95dea653798365802cf4", [:mix], [{:rustler, "~> 0.26", [hex: :rustler, repo: "hexpm", optional: false]}], "hexpm", "84b20cfe6a063edab311b2c8ff8b221698c84cbd5fbdba059e51636540142538"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [: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", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, From a4b3b0d1ce73e085c6b270624b9d820a962f9638 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 07:38:12 +0000 Subject: [PATCH 19/66] Bump minimatch from 3.0.4 to 3.0.8 in /apps/block_scout_web/assets Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.0.8. - [Release notes](https://github.com/isaacs/minimatch/releases) - [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.0.8) --- updated-dependencies: - dependency-name: minimatch dependency-type: indirect ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 40240726eadb..a0770c20f469 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -9102,6 +9102,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/globule/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/good-listener": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", @@ -12935,9 +12949,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -25383,6 +25397,19 @@ "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } } } @@ -28317,9 +28344,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, "requires": { "brace-expansion": "^1.1.7" From d25ac4b7cbba01dc17d65f923ced4361e0bb36cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Nov 2022 07:38:51 +0000 Subject: [PATCH 20/66] Bump ecto_sql from 3.9.0 to 3.9.1 Bumps [ecto_sql](https://github.com/elixir-ecto/ecto_sql) from 3.9.0 to 3.9.1. - [Release notes](https://github.com/elixir-ecto/ecto_sql/releases) - [Changelog](https://github.com/elixir-ecto/ecto_sql/blob/master/CHANGELOG.md) - [Commits](https://github.com/elixir-ecto/ecto_sql/compare/v3.9.0...v3.9.1) --- updated-dependencies: - dependency-name: ecto_sql dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- mix.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mix.lock b/mix.lock index 5844b595f942..71ced4066a1f 100644 --- a/mix.lock +++ b/mix.lock @@ -36,8 +36,8 @@ "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, "digital_token": {:hex, :digital_token, "0.4.0", "2ad6894d4a40be8b2890aad286ecd5745fa473fa5699d80361a8c94428edcd1f", [:mix], [{:cldr_utils, "~> 2.17", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a178edf61d1fee5bb3c34e14b0f4ee21809ee87cade8738f87337e59e5e66e26"}, "earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"}, - "ecto": {:hex, :ecto, "3.9.1", "67173b1687afeb68ce805ee7420b4261649d5e2deed8fe5550df23bab0bc4396", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c80bb3d736648df790f7f92f81b36c922d9dd3203ca65be4ff01d067f54eb304"}, - "ecto_sql": {:hex, :ecto_sql, "3.9.0", "2bb21210a2a13317e098a420a8c1cc58b0c3421ab8e3acfa96417dab7817918c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a8f3f720073b8b1ac4c978be25fa7960ed7fd44997420c304a4a2e200b596453"}, + "ecto": {:hex, :ecto, "3.9.2", "017db3bc786ff64271108522c01a5d3f6ba0aea5c84912cfb0dd73bf13684108", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "21466d5177e09e55289ac7eade579a642578242c7a3a9f91ad5c6583337a9d15"}, + "ecto_sql": {:hex, :ecto_sql, "3.9.1", "9bd5894eecc53d5b39d0c95180d4466aff00e10679e13a5cfa725f6f85c03c22", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fd470a4fff2e829bbf9dcceb7f3f9f6d1e49b4241e802f614de6b8b67c51118"}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ex_abi": {:hex, :ex_abi, "0.5.16", "735f14937bc3c8fd53c38f02936ef8bf93d26a0b999cb0230b105d901530acaf", [:mix], [{:ex_keccak, "~> 0.6.0", [hex: :ex_keccak, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "82ee815f438c5d29ddc3e151a23a9eb5e906f3472cc6f5005b6f5a7f37332efe"}, From 0e0931e13047ceb4e5f6728d7c10ec78e0afe5ff Mon Sep 17 00:00:00 2001 From: nikitosing <32202610+nikitosing@users.noreply.github.com> Date: Tue, 22 Nov 2022 11:16:57 +0300 Subject: [PATCH 21/66] Blockscout core API v2 (#6429) * Add tests; Fix /transactions bug * Add /internal-transactions and /logs tests * Checksum all address hashes; Done transaction_controller_test.exs * Add block_controller_test.exs * Done block_controller_test.exs * Add /counters, change /token-transfers for /addresses; Add timestamp to token transfer body * Drop params from next_page_params; Add address_controller_test.exs * Fix pending txs pagination; Add tests for address controller * Tests for address in progress * Add coin balances test for address * Done address_controller_test.exs * Done tests for API v2; Fix pagination for search; Add cache for transactions for API v2 * Add ERC filtering for transactions/0x../token-transfers; Add network utilization to /stats * Return nil for nil address_hash instead of struct * Fix token transfers * Remove decoded field from revert_reason body --- .github/workflows/config.yml | 1 + CHANGELOG.md | 2 +- .../lib/block_scout_web/api_router.ex | 1 + .../controllers/address_controller.ex | 56 +- .../controllers/api/v2/address_controller.ex | 66 +- .../controllers/api/v2/block_controller.ex | 9 +- .../controllers/api/v2/fallback_controller.ex | 5 + .../api/v2/main_page_controller.ex | 2 +- .../controllers/api/v2/stats_controller.ex | 14 +- .../api/v2/transaction_controller.ex | 66 +- .../transaction_state_controller.ex | 3 +- .../transaction_token_transfer_controller.ex | 3 +- .../lib/block_scout_web/paging_helper.ex | 40 +- .../block_scout_web/views/api/v2/helper.ex | 18 +- .../views/api/v2/token_view.ex | 6 +- .../views/api/v2/transaction_view.ex | 15 +- .../api/v2/address_controller_test.exs | 1199 +++++++++++++++++ .../api/v2/block_controller_test.exs | 329 +++++ .../api/v2/config_controller_test.exs | 22 + .../api/v2/main_page_controller_test.exs | 65 + .../api/v2/search_controller_test.exs | 147 ++ .../api/v2/stats_controller_test.exs | 57 + .../api/v2/transaction_controller_test.exs | 582 ++++++++ apps/explorer/lib/explorer/application.ex | 2 + apps/explorer/lib/explorer/chain.ex | 177 ++- .../chain/cache/transactions_api_v2.ex | 27 + .../lib/explorer/chain/token_transfer.ex | 44 +- apps/explorer/test/explorer/chain_test.exs | 2 +- apps/explorer/test/support/factory.ex | 35 + config/runtime.exs | 4 + config/runtime/test.exs | 2 + 31 files changed, 2843 insertions(+), 158 deletions(-) create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/block_controller_test.exs create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/config_controller_test.exs create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/stats_controller_test.exs create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/transaction_controller_test.exs create mode 100644 apps/explorer/lib/explorer/chain/cache/transactions_api_v2.ex diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index 738095bec3f6..9f6a71bfa981 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -582,3 +582,4 @@ jobs: ADMIN_PANEL_ENABLED: "true" ACCOUNT_ENABLED: "true" ACCOUNT_REDIS_URL: "redis://localhost:6379" + API_V2_ENABLED: "true" diff --git a/CHANGELOG.md b/CHANGELOG.md index 326765ebad1e..ff0a8a0174a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - [#6440](https://github.com/blockscout/blockscout/pull/6440) - Add support for base64 encoded NFT metadata - [#6407](https://github.com/blockscout/blockscout/pull/6407) - Indexed ratio for int txs fetching stage - [#6324](https://github.com/blockscout/blockscout/pull/6324) - Add verified contracts list page -- [#6379](https://github.com/blockscout/blockscout/pull/6379) - API v2 for frontend +- [#6379](https://github.com/blockscout/blockscout/pull/6379), [#6429](https://github.com/blockscout/blockscout/pull/6429) - API v2 for frontend - [#6351](https://github.com/blockscout/blockscout/pull/6351) - Enable forum link env var - [#6316](https://github.com/blockscout/blockscout/pull/6316) - Copy public tags functionality to master - [#6196](https://github.com/blockscout/blockscout/pull/6196) - INDEXER_CATCHUP_BLOCKS_BATCH_SIZE and INDEXER_CATCHUP_BLOCKS_CONCURRENCY env varaibles diff --git a/apps/block_scout_web/lib/block_scout_web/api_router.ex b/apps/block_scout_web/lib/block_scout_web/api_router.ex index d850b6163ec0..0d78f6f870c6 100644 --- a/apps/block_scout_web/lib/block_scout_web/api_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/api_router.ex @@ -118,6 +118,7 @@ defmodule BlockScoutWeb.ApiRouter do scope "/addresses" do get("/:address_hash", V2.AddressController, :address) + get("/:address_hash/counters", V2.AddressController, :counters) get("/:address_hash/token-balances", V2.AddressController, :token_balances) get("/:address_hash/transactions", V2.AddressController, :transactions) get("/:address_hash/token-transfers", V2.AddressController, :token_transfers) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex index b90321d16a46..982ac6128fa4 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex @@ -14,7 +14,6 @@ defmodule BlockScoutWeb.AddressController do Controller } - alias Explorer.Counters.{AddressTokenTransfersCounter, AddressTransactionsCounter, AddressTransactionsGasUsageCounter} alias Explorer.{Chain, Market} alias Explorer.Chain.Wei alias Explorer.ExchangeRates.Token @@ -148,7 +147,7 @@ defmodule BlockScoutWeb.AddressController do def address_counters(conn, %{"id" => address_hash_string}) do with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.hash_to_address(address_hash) do - {validation_count} = address_counters(address) + {validation_count} = Chain.address_counters(address) transactions_from_db = address.transactions_count || 0 token_transfers_from_db = address.token_transfers_count || 0 @@ -170,57 +169,4 @@ defmodule BlockScoutWeb.AddressController do }) end end - - defp address_counters(address) do - validation_count_task = - Task.async(fn -> - validation_count(address) - end) - - Task.start_link(fn -> - transaction_count(address) - end) - - Task.start_link(fn -> - token_transfers_count(address) - end) - - Task.start_link(fn -> - gas_usage_count(address) - end) - - [ - validation_count_task - ] - |> Task.yield_many(:infinity) - |> Enum.map(fn {_task, res} -> - case res do - {:ok, result} -> - result - - {:exit, reason} -> - raise "Query fetching address counters terminated: #{inspect(reason)}" - - nil -> - raise "Query fetching address counters timed out." - end - end) - |> List.to_tuple() - end - - def transaction_count(address) do - AddressTransactionsCounter.fetch(address) - end - - def token_transfers_count(address) do - AddressTokenTransfersCounter.fetch(address) - end - - def gas_usage_count(address) do - AddressTransactionsGasUsageCounter.fetch(address) - end - - defp validation_count(address) do - Chain.address_to_validation_count(address.hash) - end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex index 717210dc5065..5ee15da7ec68 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex @@ -9,6 +9,9 @@ defmodule BlockScoutWeb.API.V2.AddressController do current_filter: 1 ] + import BlockScoutWeb.PagingHelper, + only: [delete_parameters_from_next_page_params: 1, token_transfers_types_options: 1] + alias BlockScoutWeb.API.V2.{AddressView, BlockView, TransactionView} alias Explorer.{Chain, Market} alias Indexer.Fetcher.TokenBalanceOnDemand @@ -25,19 +28,11 @@ defmodule BlockScoutWeb.API.V2.AddressController do } ] - @transaction_with_tt_necessity_by_association [ + @token_transfer_necessity_by_association [ necessity_by_association: %{ - [created_contract_address: :names] => :optional, - [from_address: :names] => :optional, - [to_address: :names] => :optional, - [created_contract_address: :smart_contract] => :optional, - [from_address: :smart_contract] => :optional, - [to_address: :smart_contract] => :optional, - [token_transfers: :token] => :optional, - [token_transfers: :to_address] => :optional, - [token_transfers: :from_address] => :optional, - [token_transfers: :token_contract_address] => :optional, - :block => :required + :to_address => :optional, + :from_address => :optional, + :block => :optional } ] @@ -52,6 +47,24 @@ defmodule BlockScoutWeb.API.V2.AddressController do end end + def counters(conn, %{"address_hash" => address_hash_string}) do + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, + {:not_found, {:ok, address}} <- {:not_found, Chain.hash_to_address(address_hash)} do + {validation_count} = Chain.address_counters(address) + + transactions_from_db = address.transactions_count || 0 + token_transfers_from_db = address.token_transfers_count || 0 + address_gas_usage_from_db = address.gas_used || 0 + + json(conn, %{ + transaction_count: to_string(transactions_from_db), + token_transfer_count: to_string(token_transfers_from_db), + gas_usage_count: to_string(address_gas_usage_from_db), + validation_count: to_string(validation_count) + }) + end + end + def token_balances(conn, %{"address_hash" => address_hash_string}) do with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)} do token_balances = @@ -82,7 +95,8 @@ defmodule BlockScoutWeb.API.V2.AddressController do results_plus_one = Chain.address_to_transactions_with_rewards(address_hash, options) {transactions, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, transactions, params) + next_page_params = + next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -94,24 +108,26 @@ defmodule BlockScoutWeb.API.V2.AddressController do def token_transfers(conn, %{"address_hash" => address_hash_string} = params) do with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)} do options = - @transaction_with_tt_necessity_by_association + @token_transfer_necessity_by_association |> Keyword.merge(paging_options(params)) |> Keyword.merge(current_filter(params)) + |> Keyword.merge(token_transfers_types_options(params)) results_plus_one = - Chain.address_hash_to_token_transfers( + Chain.address_hash_to_token_transfers_new( address_hash, options ) {transactions, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, transactions, params) + next_page_params = + next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) |> put_view(TransactionView) - |> render(:transactions, %{transactions: transactions, next_page_params: next_page_params}) + |> render(:token_transfers, %{token_transfers: transactions, next_page_params: next_page_params}) end end @@ -134,7 +150,8 @@ defmodule BlockScoutWeb.API.V2.AddressController do results_plus_one = Chain.address_to_internal_transactions(address_hash, full_options) {internal_transactions, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, internal_transactions, params) + next_page_params = + next_page |> next_page_params(internal_transactions, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -156,7 +173,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do {logs, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, logs, params) + next_page_params = next_page |> next_page_params(logs, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -170,7 +187,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do results_plus_one = Chain.address_to_logs(address_hash, paging_options(params)) {logs, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, logs, params) + next_page_params = next_page |> next_page_params(logs, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -197,7 +214,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do results_plus_one = Chain.get_blocks_validated_by_address(full_options, address_hash) {blocks, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, blocks, params) + next_page_params = next_page |> next_page_params(blocks, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -207,14 +224,17 @@ defmodule BlockScoutWeb.API.V2.AddressController do end def coin_balance_history(conn, %{"address_hash" => address_hash_string} = params) do - with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)} do + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, + {:not_found, {:ok, _address}, _} <- + {:not_found, Chain.hash_to_address(address_hash), :empty_items_with_next_page_params} do full_options = paging_options(params) results_plus_one = Chain.address_to_coin_balances(address_hash, full_options) {coin_balances, next_page} = split_list_by_page(results_plus_one) - next_page_params = next_page_params(next_page, coin_balances, params) + next_page_params = + next_page |> next_page_params(coin_balances, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex index 24a3daf808e4..10533c1f0b59 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex @@ -4,7 +4,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, put_key_value_to_paging_options: 3, split_list_by_page: 1] - import BlockScoutWeb.PagingHelper, only: [select_block_type: 1] + import BlockScoutWeb.PagingHelper, only: [delete_parameters_from_next_page_params: 1, select_block_type: 1] alias BlockScoutWeb.API.V2.TransactionView alias BlockScoutWeb.BlockTransactionController @@ -51,7 +51,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do {blocks, next_page} = split_list_by_page(blocks_plus_one) - next_page_params = next_page_params(next_page, blocks, params) + next_page_params = next_page |> next_page_params(blocks, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -70,7 +70,10 @@ defmodule BlockScoutWeb.API.V2.BlockController do {transactions, next_page} = split_list_by_page(transactions_plus_one) - next_page_params = next_page_params(next_page, transactions, params) + next_page_params = + next_page + |> next_page_params(transactions, params) + |> delete_parameters_from_next_page_params() conn |> put_status(200) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex index 20f900066bd7..b61ef387772c 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex @@ -10,6 +10,11 @@ defmodule BlockScoutWeb.API.V2.FallbackController do |> render(:message, %{message: "Invalid parameter(s)"}) end + def call(conn, {:not_found, _, :empty_items_with_next_page_params}) do + conn + |> json(%{"items" => [], "next_page_params" => nil}) + end + def call(conn, {:not_found, _}) do conn |> put_status(:not_found) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex index 417eaf4009a8..0d49281f7f84 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex @@ -29,7 +29,7 @@ defmodule BlockScoutWeb.API.V2.MainPageController do [from_address: :smart_contract] => :optional, [to_address: :smart_contract] => :optional }, - paging_options: %PagingOptions{page_size: 5} + paging_options: %PagingOptions{page_size: 6} ) conn diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex index fa1a46a0c4e0..7624d3574cd1 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex @@ -50,11 +50,23 @@ defmodule BlockScoutWeb.API.V2.StatsController do "gas_used_today" => Enum.at(transaction_stats, 0).gas_used, "gas_prices" => gas_prices, "static_gas_price" => gas_price, - "market_cap" => Helper.market_cap(market_cap_type, exchange_rate) + "market_cap" => Helper.market_cap(market_cap_type, exchange_rate), + "network_utilization_percentage" => network_utilization_percentage() } ) end + defp network_utilization_percentage do + {gas_used, gas_limit} = + Enum.reduce(Chain.list_blocks(), {Decimal.new(0), Decimal.new(0)}, fn block, {gas_used, gas_limit} -> + {Decimal.add(gas_used, block.gas_used), Decimal.add(gas_limit, block.gas_limit)} + end) + + if Decimal.compare(gas_limit, 0) == :eq, + do: 0, + else: gas_used |> Decimal.div(gas_limit) |> Decimal.mult(100) |> Decimal.to_float() + end + def transactions_chart(conn, _params) do [{:history_size, history_size}] = Application.get_env(:block_scout_web, BlockScoutWeb.Chain.TransactionHistoryChartController, [{:history_size, 30}]) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex index cce9bd771847..4b6a6c95992c 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex @@ -4,7 +4,14 @@ defmodule BlockScoutWeb.API.V2.TransactionController do import BlockScoutWeb.Chain, only: [next_page_params: 3, paging_options: 1, split_list_by_page: 1] import BlockScoutWeb.PagingHelper, - only: [paging_options: 2, filter_options: 1, method_filter_options: 1, type_filter_options: 1] + only: [ + delete_parameters_from_next_page_params: 1, + paging_options: 2, + filter_options: 2, + method_filter_options: 1, + token_transfers_types_options: 1, + type_filter_options: 1 + ] alias Explorer.Chain alias Explorer.Chain.Import @@ -22,6 +29,15 @@ defmodule BlockScoutWeb.API.V2.TransactionController do } @token_transfers_neccessity_by_association %{ + [from_address: :smart_contract] => :optional, + [to_address: :smart_contract] => :optional, + [from_address: :names] => :optional, + [to_address: :names] => :optional, + from_address: :required, + to_address: :required + } + + @token_transfers_in_tx_neccessity_by_association %{ [from_address: :smart_contract] => :optional, [to_address: :smart_contract] => :optional, [from_address: :names] => :optional, @@ -51,7 +67,8 @@ defmodule BlockScoutWeb.API.V2.TransactionController do transaction_hash, necessity_by_association: @transaction_necessity_by_association )}, - preloaded <- Chain.preload_token_transfers(transaction, @token_transfers_neccessity_by_association, false) do + preloaded <- + Chain.preload_token_transfers(transaction, @token_transfers_in_tx_neccessity_by_association, false) do conn |> put_status(200) |> render(:transaction, %{transaction: preloaded}) @@ -59,24 +76,21 @@ defmodule BlockScoutWeb.API.V2.TransactionController do end def transactions(conn, params) do - filter_options = filter_options(params) - method_filter_options = method_filter_options(params) - type_filter_options = type_filter_options(params) + filter_options = filter_options(params, :validated) full_options = - Keyword.merge( - [ - necessity_by_association: @transaction_necessity_by_association - ], - paging_options(params, filter_options) - ) + [ + necessity_by_association: @transaction_necessity_by_association + ] + |> Keyword.merge(paging_options(params, filter_options)) + |> Keyword.merge(method_filter_options(params)) + |> Keyword.merge(type_filter_options(params)) - transactions_plus_one = - Chain.recent_transactions(full_options, filter_options, method_filter_options, type_filter_options) + transactions_plus_one = Chain.recent_transactions(full_options, filter_options) {transactions, next_page} = split_list_by_page(transactions_plus_one) - next_page_params = next_page_params(next_page, transactions, params) + next_page_params = next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -146,18 +160,18 @@ defmodule BlockScoutWeb.API.V2.TransactionController do def token_transfers(conn, %{"transaction_hash" => transaction_hash_string} = params) do with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)} do full_options = - Keyword.merge( - [ - necessity_by_association: @token_transfers_neccessity_by_association - ], - paging_options(params) - ) + [necessity_by_association: @token_transfers_neccessity_by_association] + |> Keyword.merge(paging_options(params)) + |> Keyword.merge(token_transfers_types_options(params)) token_transfers_plus_one = Chain.transaction_to_token_transfers(transaction_hash, full_options) {token_transfers, next_page} = split_list_by_page(token_transfers_plus_one) - next_page_params = next_page_params(next_page, token_transfers, params) + next_page_params = + next_page + |> next_page_params(token_transfers, params) + |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -177,7 +191,10 @@ defmodule BlockScoutWeb.API.V2.TransactionController do {internal_transactions, next_page} = split_list_by_page(internal_transactions_plus_one) - next_page_params = next_page_params(next_page, internal_transactions, params) + next_page_params = + next_page + |> next_page_params(internal_transactions, params) + |> delete_parameters_from_next_page_params() conn |> put_status(200) @@ -207,7 +224,10 @@ defmodule BlockScoutWeb.API.V2.TransactionController do {logs, next_page} = split_list_by_page(logs_plus_one) - next_page_params = next_page_params(next_page, logs, params) + next_page_params = + next_page + |> next_page_params(logs, params) + |> delete_parameters_from_next_page_params() conn |> put_status(200) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex index 14b07de0409d..4a7905d71cc8 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex @@ -43,8 +43,7 @@ defmodule BlockScoutWeb.TransactionStateController do [from_address: :names] => :optional, [to_address: :names] => :optional, from_address: :required, - to_address: :required, - token: :required + to_address: :required }, # we need to consider all token transfers in block to show whole state change of transaction paging_options: %PagingOptions{key: nil, page_size: nil} diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex index 931df3ce9441..6ea80b6a0319 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex @@ -33,8 +33,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do [from_address: :names] => :optional, [to_address: :names] => :optional, from_address: :required, - to_address: :required, - token: :required + to_address: :required } ], paging_options(params) diff --git a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex index 3f44c6d62acf..9b0b37224018 100644 --- a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex +++ b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex @@ -9,6 +9,7 @@ defmodule BlockScoutWeb.PagingHelper do @default_paging_options %PagingOptions{page_size: @page_size + 1} @allowed_filter_labels ["validated", "pending"] @allowed_type_labels ["coin_transfer", "contract_call", "contract_creation", "token_transfer", "token_creation"] + @allowed_token_transfer_type_labels ["ERC-20", "ERC-721", "ERC-1155"] def paging_options(%{"block_number" => block_number_string, "index" => index_string}, [:validated | _]) do with {block_number, ""} <- Integer.parse(block_number_string), @@ -32,23 +33,34 @@ defmodule BlockScoutWeb.PagingHelper do def paging_options(_params, _filter), do: [paging_options: @default_paging_options] - def filter_options(%{"filter" => filter}) do - parse_filter(filter, @allowed_filter_labels) + def token_transfers_types_options(%{"type" => filters}) do + [ + token_type: filters |> String.upcase() |> parse_filter(@allowed_token_transfer_type_labels) + ] + end + + def token_transfers_types_options(_), do: [token_type: []] + + # sobelow_skip ["DOS.StringToAtom"] + def filter_options(%{"filter" => filter}, fallback) do + filter = filter |> parse_filter(@allowed_filter_labels) |> Enum.map(&String.to_atom/1) + if(filter == [], do: [fallback], else: filter) end - def filter_options(_params), do: [] + def filter_options(_params, fallback), do: [fallback] + # sobelow_skip ["DOS.StringToAtom"] def type_filter_options(%{"type" => type}) do - parse_filter(type, @allowed_type_labels) + [type: type |> parse_filter(@allowed_type_labels) |> Enum.map(&String.to_atom/1)] end - def type_filter_options(_params), do: [] + def type_filter_options(_params), do: [type: []] def method_filter_options(%{"method" => method}) do - parse_method_filter(method) + [method: parse_method_filter(method)] end - def method_filter_options(_params), do: [] + def method_filter_options(_params), do: [method: []] def parse_filter("[" <> filter, allowed_labels) do filter @@ -56,13 +68,11 @@ defmodule BlockScoutWeb.PagingHelper do |> parse_filter(allowed_labels) end - # sobelow_skip ["DOS.StringToAtom"] def parse_filter(filter, allowed_labels) when is_binary(filter) do filter |> String.split(",") |> Enum.filter(fn label -> Enum.member?(allowed_labels, label) end) |> Enum.uniq() - |> Enum.map(&String.to_atom/1) end def parse_method_filter("[" <> filter) do @@ -114,4 +124,16 @@ defmodule BlockScoutWeb.PagingHelper do }, block_type: "Block" ] + + def delete_parameters_from_next_page_params(params) when is_map(params) do + params + |> Map.delete("block_hash_or_number") + |> Map.delete("transaction_hash") + |> Map.delete("address_hash") + |> Map.delete("type") + |> Map.delete("method") + |> Map.delete("filter") + end + + def delete_parameters_from_next_page_params(_), do: nil end 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 57f914bc0ce1..6dc1808e318b 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 @@ -10,6 +10,10 @@ defmodule BlockScoutWeb.API.V2.Helper do import BlockScoutWeb.Account.AuthController, only: [current_user: 1] import BlockScoutWeb.Models.GetAddressTags, only: [get_address_tags: 2, get_tags_on_address: 1] + def address_with_info(_, _, nil) do + nil + end + def address_with_info(conn, address, address_hash) do %{ personal_tags: private_tags, @@ -27,7 +31,7 @@ defmodule BlockScoutWeb.API.V2.Helper do def address_with_info(%Address{} = address, _address_hash) do %{ - "hash" => to_string(address), + "hash" => Address.checksum(address), "is_contract" => is_smart_contract(address), "name" => address_name(address), "implementation_name" => implementation_name(address), @@ -39,8 +43,18 @@ defmodule BlockScoutWeb.API.V2.Helper do address_with_info(nil, address_hash) end + def address_with_info(nil, nil) do + nil + end + def address_with_info(nil, address_hash) do - %{"hash" => address_hash, "is_contract" => false, "name" => nil, "implementation_name" => nil, "is_verified" => nil} + %{ + "hash" => Address.checksum(address_hash), + "is_contract" => false, + "name" => nil, + "implementation_name" => nil, + "is_verified" => nil + } end def address_name(%Address{names: [_ | _] = address_names}) do diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex index e0bdae9c989f..1806ec9d3371 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex @@ -1,12 +1,14 @@ defmodule BlockScoutWeb.API.V2.TokenView do + alias Explorer.Chain.Address + def render("token.json", %{token: token}) do %{ - "address" => token.contract_address_hash, + "address" => Address.checksum(token.contract_address_hash), "symbol" => token.symbol, "name" => token.name, "decimals" => token.decimals, "type" => token.type, - "holders" => to_string(token.holder_count), + "holders" => token.holder_count && to_string(token.holder_count), "exchange_rate" => token.usd_value && to_string(token.usd_value) } end 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 c2f85b2ba62f..651547ba7f3c 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 @@ -43,8 +43,8 @@ defmodule BlockScoutWeb.API.V2.TransactionView do %{"method_id" => method_id, "method_call" => text, "parameters" => prepare_method_mapping(mapping)} end - def render("revert_reason.json", %{raw: raw, decoded: decoded}) do - %{"raw" => raw, "decoded" => decoded} + def render("revert_reason.json", %{raw: raw}) do + %{"raw" => raw} end def render("token_transfers.json", %{token_transfers: token_transfers, next_page_params: next_page_params, conn: conn}) do @@ -88,7 +88,8 @@ defmodule BlockScoutWeb.API.V2.TransactionView do "to" => Helper.address_with_info(conn, token_transfer.to_address, token_transfer.to_address_hash), "total" => prepare_token_transfer_total(token_transfer), "token" => TokenView.render("token.json", %{token: Market.add_price(token_transfer.token)}), - "type" => Chain.get_token_transfer_type(token_transfer) + "type" => Chain.get_token_transfer_type(token_transfer), + "timestamp" => block_timestamp(token_transfer.block) } end @@ -204,7 +205,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do "result" => status, "status" => transaction.status, "block" => transaction.block_number, - "timestamp" => transaction.block && transaction.block.timestamp, + "timestamp" => block_timestamp(transaction.block), "from" => Helper.address_with_info(conn, transaction.from_address, transaction.from_address_hash), "to" => Helper.address_with_info(conn, transaction.to_address, transaction.to_address_hash), "created_contract" => @@ -286,8 +287,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do _ -> hex = TransactionView.get_pure_transaction_revert_reason(transaction) - utf8 = TransactionView.decoded_revert_reason(transaction) - render(__MODULE__, "revert_reason.json", raw: hex, decoded: utf8) + render(__MODULE__, "revert_reason.json", raw: hex) end end end @@ -444,4 +444,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do types end end + + defp block_timestamp(%Block{} = block), do: block.timestamp + defp block_timestamp(_), do: nil end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs new file mode 100644 index 000000000000..7542666ecaad --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs @@ -0,0 +1,1199 @@ +defmodule BlockScoutWeb.API.V2.AddressControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.{Chain, Repo} + + alias Explorer.Chain.{ + Address, + Address.CoinBalance, + Block, + InternalTransaction, + Log, + Token, + TokenTransfer, + Transaction + } + + alias Explorer.Chain.Address.CurrentTokenBalance + + describe "/addresses/{address_hash}" do + test "get 404 on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}") + + assert %{"message" => "Not found"} = json_response(request, 404) + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get address & get the same response for checksummed and downcased parameter", %{conn: conn} do + address = insert(:address) + + correct_reponse = %{ + "hash" => Address.checksum(address.hash), + "implementation_name" => nil, + "is_contract" => false, + "is_verified" => false, + "name" => nil, + "private_tags" => [], + "public_tags" => [], + "watchlist_names" => [] + } + + request = get(conn, "/api/v2/addresses/#{Address.checksum(address.hash)}") + assert ^correct_reponse = json_response(request, 200) + + request = get(conn, "/api/v2/addresses/#{String.downcase(to_string(address.hash))}") + assert ^correct_reponse = json_response(request, 200) + end + end + + describe "/addresses/{address_hash}/counters" do + test "get 404 on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/counters") + + assert %{"message" => "Not found"} = json_response(request, 404) + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/counters") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get counters with 0s", %{conn: conn} do + address = insert(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/counters") + + assert %{ + "transaction_count" => "0", + "token_transfer_count" => "0", + "gas_usage_count" => "0", + "validation_count" => "0" + } = json_response(request, 200) + end + + test "get counters", %{conn: conn} do + address = insert(:address) + + tx_from = insert(:transaction, from_address: address) |> with_block() + insert(:transaction, to_address: address) |> with_block() + another_tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + from_address: address, + transaction: another_tx, + block: another_tx.block, + block_number: another_tx.block_number + ) + + insert(:token_transfer, + to_address: address, + transaction: another_tx, + block: another_tx.block, + block_number: another_tx.block_number + ) + + insert(:block, miner: address) + + Chain.transaction_count(address) + Chain.token_transfers_count(address) + Chain.gas_usage_count(address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/counters") + + gas_used = to_string(tx_from.gas_used) + + assert %{ + "transaction_count" => "2", + "token_transfer_count" => "2", + "gas_usage_count" => ^gas_used, + "validation_count" => "1" + } = json_response(request, 200) + end + end + + describe "/addresses/{address_hash}/transactions" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/transactions") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get relevant transaction", %{conn: conn} do + address = insert(:address) + + tx = insert(:transaction, from_address: address) |> with_block() + + insert(:transaction) |> with_block() + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(tx, Enum.at(response["items"], 0)) + end + + test "get pending transaction", %{conn: conn} do + address = insert(:address) + + tx = insert(:transaction, from_address: address) |> with_block() + pending_tx = insert(:transaction, from_address: address) + + insert(:transaction) |> with_block() + insert(:transaction) + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 2 + assert response["next_page_params"] == nil + compare_item(pending_tx, Enum.at(response["items"], 0)) + compare_item(tx, Enum.at(response["items"], 1)) + end + + test "get only :to transaction", %{conn: conn} do + address = insert(:address) + + insert(:transaction, from_address: address) |> with_block() + tx = insert(:transaction, to_address: address) |> with_block() + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions", %{"filter" => "to"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(tx, Enum.at(response["items"], 0)) + end + + test "get only :from transactions", %{conn: conn} do + address = insert(:address) + + tx = insert(:transaction, from_address: address) |> with_block() + insert(:transaction, to_address: address) |> with_block() + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions", %{"filter" => "from"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(tx, Enum.at(response["items"], 0)) + end + + test "validated txs can paginate", %{conn: conn} do + address = insert(:address) + + txs = insert_list(51, :transaction, from_address: address) |> with_block() + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/transactions", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, txs) + end + + test "pending txs can paginate", %{conn: conn} do + address = insert(:address) + + txs = insert_list(51, :transaction, from_address: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/transactions", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, txs) + end + + test "pending + validated txs can paginate", %{conn: conn} do + address = insert(:address) + + txs_pending = insert_list(51, :transaction, from_address: address) + txs_validated = insert_list(50, :transaction, to_address: address) |> with_block() + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/transactions", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(txs_pending, 50), Enum.at(response["items"], 0)) + compare_item(Enum.at(txs_pending, 1), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 50 + assert response_2nd_page["next_page_params"] != nil + compare_item(Enum.at(txs_pending, 0), Enum.at(response_2nd_page["items"], 0)) + compare_item(Enum.at(txs_validated, 49), Enum.at(response_2nd_page["items"], 1)) + compare_item(Enum.at(txs_validated, 1), Enum.at(response_2nd_page["items"], 49)) + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions", response_2nd_page["next_page_params"]) + assert response = json_response(request, 200) + + check_paginated_response(response_2nd_page, response, txs_validated ++ [Enum.at(txs_pending, 0)]) + end + + test ":to txs can paginate", %{conn: conn} do + address = insert(:address) + + txs = insert_list(51, :transaction, to_address: address) |> with_block() + insert_list(51, :transaction, from_address: address) |> with_block() + + filter = %{"filter" => "to"} + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/transactions", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, txs) + end + + test ":from txs can paginate", %{conn: conn} do + address = insert(:address) + + insert_list(51, :transaction, to_address: address) |> with_block() + txs = insert_list(51, :transaction, from_address: address) |> with_block() + + filter = %{"filter" => "from"} + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/transactions", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, txs) + end + + test ":from + :to txs can paginate", %{conn: conn} do + address = insert(:address) + + txs_from = insert_list(50, :transaction, from_address: address) |> with_block() + txs_to = insert_list(51, :transaction, to_address: address) |> with_block() + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/transactions", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(txs_to, 50), Enum.at(response["items"], 0)) + compare_item(Enum.at(txs_to, 1), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 50 + assert response_2nd_page["next_page_params"] != nil + compare_item(Enum.at(txs_to, 0), Enum.at(response_2nd_page["items"], 0)) + compare_item(Enum.at(txs_from, 49), Enum.at(response_2nd_page["items"], 1)) + compare_item(Enum.at(txs_from, 1), Enum.at(response_2nd_page["items"], 49)) + + request = get(conn, "/api/v2/addresses/#{address.hash}/transactions", response_2nd_page["next_page_params"]) + assert response = json_response(request, 200) + + check_paginated_response(response_2nd_page, response, txs_from ++ [Enum.at(txs_to, 0)]) + end + end + + describe "/addresses/{address_hash}/token-transfers" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/token-transfers") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get relevant token transfer", %{conn: conn} do + address = insert(:address) + + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number) + + token_transfer = + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(token_transfer, Enum.at(response["items"], 0)) + end + + test "get only :to token transfer", %{conn: conn} do + address = insert(:address) + + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + + token_transfer = + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, to_address: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", %{"filter" => "to"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(token_transfer, Enum.at(response["items"], 0)) + end + + test "get only :from token transfer", %{conn: conn} do + address = insert(:address) + + tx = insert(:transaction) |> with_block() + + token_transfer = + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, to_address: address) + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", %{"filter" => "from"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(token_transfer, Enum.at(response["items"], 0)) + end + + test "token transfers can paginate", %{conn: conn} do + address = insert(:address) + + token_tranfers = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + end + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, token_tranfers) + end + + test ":to token transfers can paginate", %{conn: conn} do + address = insert(:address) + + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + end + + token_tranfers = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, to_address: address) + end + + filter = %{"filter" => "to"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, token_tranfers) + end + + test ":from token transfers can paginate", %{conn: conn} do + address = insert(:address) + + token_tranfers = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + end + + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, to_address: address) + end + + filter = %{"filter" => "from"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, token_tranfers) + end + + test ":from + :to tt can paginate", %{conn: conn} do + address = insert(:address) + + tt_from = + for _ <- 0..49 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, from_address: address) + end + + tt_to = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number, to_address: address) + end + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(tt_to, 50), Enum.at(response["items"], 0)) + compare_item(Enum.at(tt_to, 1), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 50 + assert response_2nd_page["next_page_params"] != nil + compare_item(Enum.at(tt_to, 0), Enum.at(response_2nd_page["items"], 0)) + compare_item(Enum.at(tt_from, 49), Enum.at(response_2nd_page["items"], 1)) + compare_item(Enum.at(tt_from, 1), Enum.at(response_2nd_page["items"], 49)) + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", response_2nd_page["next_page_params"]) + assert response = json_response(request, 200) + + check_paginated_response(response_2nd_page, response, tt_from ++ [Enum.at(tt_to, 0)]) + end + + test "check token type filters", %{conn: conn} do + address = insert(:address) + + erc_20_token = insert(:token, type: "ERC-20") + + erc_20_tt = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + from_address: address, + token_contract_address: erc_20_token.contract_address + ) + end + + erc_721_token = insert(:token, type: "ERC-721") + + erc_721_tt = + for x <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + from_address: address, + token_contract_address: erc_721_token.contract_address, + token_ids: [x] + ) + end + + erc_1155_token = insert(:token, type: "ERC-1155") + + erc_1155_tt = + for x <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + from_address: address, + token_contract_address: erc_1155_token.contract_address, + token_ids: [x] + ) + end + + # -- ERC-20 -- + filter = %{"type" => "ERC-20"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_20_tt) + # -- ------ -- + + # -- ERC-721 -- + filter = %{"type" => "ERC-721"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_721_tt) + # -- ------ -- + + # -- ERC-1155 -- + filter = %{"type" => "ERC-1155"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_1155_tt) + # -- ------ -- + + # two filters simultaneously + filter = %{"type" => "ERC-1155,ERC-20"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(erc_1155_tt, 50), Enum.at(response["items"], 0)) + compare_item(Enum.at(erc_1155_tt, 1), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 50 + assert response_2nd_page["next_page_params"] != nil + compare_item(Enum.at(erc_1155_tt, 0), Enum.at(response_2nd_page["items"], 0)) + compare_item(Enum.at(erc_20_tt, 50), Enum.at(response_2nd_page["items"], 1)) + compare_item(Enum.at(erc_20_tt, 2), Enum.at(response_2nd_page["items"], 49)) + + request_3rd_page = + get( + conn, + "/api/v2/addresses/#{address.hash}/token-transfers", + Map.merge(response_2nd_page["next_page_params"], filter) + ) + + assert response_3rd_page = json_response(request_3rd_page, 200) + assert Enum.count(response_3rd_page["items"]) == 2 + assert response_3rd_page["next_page_params"] == nil + compare_item(Enum.at(erc_20_tt, 1), Enum.at(response_3rd_page["items"], 0)) + compare_item(Enum.at(erc_20_tt, 0), Enum.at(response_3rd_page["items"], 1)) + # -- ------ -- + end + + test "type and direction filters at the same time", %{conn: conn} do + address = insert(:address) + + erc_20_token = insert(:token, type: "ERC-20") + + erc_20_tt = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + from_address: address, + token_contract_address: erc_20_token.contract_address + ) + end + + erc_721_token = insert(:token, type: "ERC-721") + + erc_721_tt = + for x <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + to_address: address, + token_contract_address: erc_721_token.contract_address, + token_ids: [x] + ) + end + + filter = %{"type" => "ERC-721", "filter" => "from"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + + filter = %{"type" => "ERC-721", "filter" => "to"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_721_tt) + + filter = %{"type" => "ERC-721,ERC-20", "filter" => "to"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_721_tt) + + filter = %{"type" => "ERC-721,ERC-20", "filter" => "from"} + request = get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/token-transfers", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_20_tt) + end + end + + describe "/addresses/{address_hash}/internal-transactions" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/internal-transactions") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get internal tx and filter working", %{conn: conn} do + address = insert(:address) + + tx = + :transaction + |> insert() + |> with_block() + + internal_tx_from = + insert(:internal_transaction, + transaction: tx, + index: 1, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: 1, + from_address: address + ) + + internal_tx_to = + insert(:internal_transaction, + transaction: tx, + index: 2, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: 2, + to_address: address + ) + + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 2 + assert response["next_page_params"] == nil + + compare_item(internal_tx_from, Enum.at(response["items"], 1)) + compare_item(internal_tx_to, Enum.at(response["items"], 0)) + + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions", %{"filter" => "from"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(internal_tx_from, Enum.at(response["items"], 0)) + + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions", %{"filter" => "to"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(internal_tx_to, Enum.at(response["items"], 0)) + end + + test "internal txs can paginate", %{conn: conn} do + address = insert(:address) + + tx = + :transaction + |> insert() + |> with_block() + + itxs_from = + for i <- 1..51 do + insert(:internal_transaction, + transaction: tx, + index: i, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: i, + from_address: address + ) + end + + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions") + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, itxs_from) + + itxs_to = + for i <- 52..102 do + insert(:internal_transaction, + transaction: tx, + index: i, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: i, + to_address: address + ) + end + + filter = %{"filter" => "to"} + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/addresses/#{address.hash}/internal-transactions", + Map.merge(response["next_page_params"], filter) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, itxs_to) + + filter = %{"filter" => "from"} + request = get(conn, "/api/v2/addresses/#{address.hash}/internal-transactions", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/addresses/#{address.hash}/internal-transactions", + Map.merge(response["next_page_params"], filter) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, itxs_from) + end + end + + describe "/addresses/{address_hash}/blocks-validated" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/blocks-validated") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/blocks-validated") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get relevant block validated", %{conn: conn} do + address = insert(:address) + insert(:block) + block = insert(:block, miner: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/blocks-validated") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + compare_item(block, Enum.at(response["items"], 0)) + end + + test "blocks validated can be paginated", %{conn: conn} do + address = insert(:address) + insert(:block) + blocks = insert_list(51, :block, miner: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/blocks-validated") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/blocks-validated", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, blocks) + end + end + + describe "/addresses/{address_hash}/token-balances" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-balances") + + assert response = json_response(request, 200) + assert response == [] + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/token-balances") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get token balance", %{conn: conn} do + address = insert(:address) + + ctbs = + for _ <- 0..50 do + insert(:address_current_token_balance_with_token_id, address: address) |> Repo.preload([:token]) + end + |> Enum.sort_by(fn x -> x.value end, :desc) + + request = get(conn, "/api/v2/addresses/#{address.hash}/token-balances") + + assert response = json_response(request, 200) + + for i <- 0..50 do + compare_item(Enum.at(ctbs, i), Enum.at(response, i)) + end + end + end + + describe "/addresses/{address_hash}/coin-balance-history" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/coin-balance-history") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/coin-balance-history") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get coin balance history", %{conn: conn} do + address = insert(:address) + + insert(:address_coin_balance) + acb = insert(:address_coin_balance, address: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/coin-balance-history") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + compare_item(acb, Enum.at(response["items"], 0)) + end + + test "coin balance history can paginate", %{conn: conn} do + address = insert(:address) + + acbs = insert_list(51, :address_coin_balance, address: address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/coin-balance-history") + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/addresses/#{address.hash}/coin-balance-history", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, acbs) + end + end + + describe "/addresses/{address_hash}/coin-balance-history-by-day" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/coin-balance-history-by-day") + + assert response = json_response(request, 200) + assert response == [] + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/coin-balance-history-by-day") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get coin balance history by day", %{conn: conn} do + address = insert(:address) + noon = Timex.now() |> Timex.beginning_of_day() |> Timex.set(hour: 12) + block = insert(:block, timestamp: noon, number: 2) + block_one_day_ago = insert(:block, timestamp: Timex.shift(noon, days: -1), number: 1) + insert(:fetched_balance, address_hash: address.hash, value: 1000, block_number: block.number) + insert(:fetched_balance, address_hash: address.hash, value: 2000, block_number: block_one_day_ago.number) + insert(:fetched_balance_daily, address_hash: address.hash, value: 1000, day: noon) + insert(:fetched_balance_daily, address_hash: address.hash, value: 2000, day: Timex.shift(noon, days: -1)) + + request = get(conn, "/api/v2/addresses/#{address.hash}/coin-balance-history-by-day") + + response = json_response(request, 200) + + assert [ + %{"date" => _, "value" => "2000"}, + %{"date" => _, "value" => "1000"}, + %{"date" => _, "value" => "1000"} + ] = response + end + end + + describe "/addresses/{address_hash}/logs" do + test "get empty list on non existing address", %{conn: conn} do + address = build(:address) + + request = get(conn, "/api/v2/addresses/#{address.hash}/logs") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/addresses/0x/logs") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get log", %{conn: conn} do + address = insert(:address) + + tx = + :transaction + |> insert() + |> with_block() + + log = + insert(:log, + transaction: tx, + index: 1, + block: tx.block, + block_number: tx.block_number, + address: address + ) + + request = get(conn, "/api/v2/addresses/#{address.hash}/logs") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(log, Enum.at(response["items"], 0)) + end + + # for some reasons test does not work if run as single test + test "logs can paginate", %{conn: conn} do + address = insert(:address) + + logs = + for x <- 0..50 do + tx = + :transaction + |> insert() + |> with_block() + + insert(:log, + transaction: tx, + index: x, + block: tx.block, + block_number: tx.block_number, + address: address + ) + end + + request = get(conn, "/api/v2/addresses/#{address.hash}/logs") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/addresses/#{address.hash}/logs", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + check_paginated_response(response, response_2nd_page, logs) + end + + test "logs can be filtered by topic", %{conn: conn} do + address = insert(:address) + + for x <- 0..20 do + tx = + :transaction + |> insert() + |> with_block() + + insert(:log, + transaction: tx, + index: x, + block: tx.block, + block_number: tx.block_number, + address: address + ) + end + + tx = + :transaction + |> insert() + |> with_block() + + log = + insert(:log, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + address: address, + first_topic: "0x123456789123456789" + ) + + request = get(conn, "/api/v2/addresses/#{address.hash}/logs?topic=0x123456789123456789") + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(log, Enum.at(response["items"], 0)) + end + end + + defp compare_item(%Transaction{} = transaction, json) do + assert to_string(transaction.hash) == json["hash"] + assert transaction.block_number == json["block"] + assert to_string(transaction.value.value) == json["value"] + assert Address.checksum(transaction.from_address_hash) == json["from"]["hash"] + assert Address.checksum(transaction.to_address_hash) == json["to"]["hash"] + end + + defp compare_item(%TokenTransfer{} = token_transfer, json) do + assert Address.checksum(token_transfer.from_address_hash) == json["from"]["hash"] + assert Address.checksum(token_transfer.to_address_hash) == json["to"]["hash"] + assert to_string(token_transfer.transaction_hash) == json["tx_hash"] + end + + defp compare_item(%InternalTransaction{} = internal_tx, json) do + assert internal_tx.block_number == json["block"] + assert to_string(internal_tx.gas) == json["gas_limit"] + assert internal_tx.index == json["index"] + assert to_string(internal_tx.transaction_hash) == json["transaction_hash"] + assert Address.checksum(internal_tx.from_address_hash) == json["from"]["hash"] + assert Address.checksum(internal_tx.to_address_hash) == json["to"]["hash"] + end + + defp compare_item(%Block{} = block, json) do + assert to_string(block.hash) == json["hash"] + assert block.number == json["height"] + end + + defp compare_item(%CurrentTokenBalance{} = ctb, json) do + assert to_string(ctb.value) == json["value"] + assert (ctb.token_id && to_string(ctb.token_id)) == json["token_id"] + compare_item(ctb.token, json["token"]) + end + + defp compare_item(%CoinBalance{} = cb, json) do + assert to_string(cb.value.value) == json["value"] + assert cb.block_number == json["block_number"] + + assert Jason.encode!(Repo.get_by(Block, number: cb.block_number).timestamp) =~ + String.replace(json["block_timestamp"], "Z", "") + end + + defp compare_item(%Token{} = token, json) do + assert Address.checksum(token.contract_address_hash) == json["address"] + assert to_string(token.symbol) == json["symbol"] + assert to_string(token.name) == json["name"] + assert to_string(token.type) == json["type"] + assert to_string(token.decimals) == json["decimals"] + assert (token.holder_count && to_string(token.holder_count)) == json["holders"] + assert Map.has_key?(json, "exchange_rate") + end + + defp compare_item(%Log{} = log, json) do + assert to_string(log.data) == json["data"] + assert log.index == json["index"] + assert Address.checksum(log.address_hash) == json["address"]["hash"] + end + + defp check_paginated_response(first_page_resp, second_page_resp, list) do + assert Enum.count(first_page_resp["items"]) == 50 + assert first_page_resp["next_page_params"] != nil + compare_item(Enum.at(list, 50), Enum.at(first_page_resp["items"], 0)) + compare_item(Enum.at(list, 1), Enum.at(first_page_resp["items"], 49)) + + assert Enum.count(second_page_resp["items"]) == 1 + assert second_page_resp["next_page_params"] == nil + compare_item(Enum.at(list, 0), Enum.at(second_page_resp["items"], 0)) + end +end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/block_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/block_controller_test.exs new file mode 100644 index 000000000000..d16e457441bf --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/block_controller_test.exs @@ -0,0 +1,329 @@ +defmodule BlockScoutWeb.API.V2.BlockControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.Chain.{Address, Block, Transaction} + + setup do + Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) + Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Uncles.child_id()) + + :ok + end + + describe "/blocks" do + test "empty lists", %{conn: conn} do + request = get(conn, "/api/v2/blocks") + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + + request = get(conn, "/api/v2/blocks", %{"type" => "uncle"}) + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + + request = get(conn, "/api/v2/blocks", %{"type" => "reorg"}) + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + + request = get(conn, "/api/v2/blocks", %{"type" => "block"}) + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get block", %{conn: conn} do + block = insert(:block) + + request = get(conn, "/api/v2/blocks") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(block, Enum.at(response["items"], 0)) + end + + test "type=block returns only consensus blocks", %{conn: conn} do + blocks = + 4 + |> insert_list(:block) + |> Enum.reverse() + + for index <- 0..3 do + uncle = insert(:block, consensus: false) + insert(:block_second_degree_relation, uncle_hash: uncle.hash, nephew: Enum.at(blocks, index)) + end + + 2 + |> insert_list(:block, consensus: false) + + request = get(conn, "/api/v2/blocks", %{"type" => "block"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 4 + assert response["next_page_params"] == nil + + for index <- 0..3 do + compare_item(Enum.at(blocks, index), Enum.at(response["items"], index)) + end + end + + test "type=block can paginate", %{conn: conn} do + blocks = + 51 + |> insert_list(:block) + + filter = %{"type" => "block"} + + request = get(conn, "/api/v2/blocks", filter) + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/blocks", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, blocks) + end + + test "type=reorg returns only non consensus blocks", %{conn: conn} do + blocks = + 5 + |> insert_list(:block) + + for index <- 0..3 do + uncle = insert(:block, consensus: false) + insert(:block_second_degree_relation, uncle_hash: uncle.hash, nephew: Enum.at(blocks, index)) + end + + reorgs = + 4 + |> insert_list(:block, consensus: false) + |> Enum.reverse() + + request = get(conn, "/api/v2/blocks", %{"type" => "reorg"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 4 + assert response["next_page_params"] == nil + + for index <- 0..3 do + compare_item(Enum.at(reorgs, index), Enum.at(response["items"], index)) + end + end + + test "type=reorg can paginate", %{conn: conn} do + reorgs = + 51 + |> insert_list(:block, consensus: false) + + filter = %{"type" => "reorg"} + request = get(conn, "/api/v2/blocks", filter) + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/blocks", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, reorgs) + end + + test "type=uncle returns only uncle blocks", %{conn: conn} do + blocks = + 4 + |> insert_list(:block) + |> Enum.reverse() + + uncles = + for index <- 0..3 do + uncle = insert(:block, consensus: false) + insert(:block_second_degree_relation, uncle_hash: uncle.hash, nephew: Enum.at(blocks, index)) + uncle + end + |> Enum.reverse() + + 4 + |> insert_list(:block, consensus: false) + + request = get(conn, "/api/v2/blocks", %{"type" => "uncle"}) + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 4 + assert response["next_page_params"] == nil + + for index <- 0..3 do + compare_item(Enum.at(uncles, index), Enum.at(response["items"], index)) + end + end + + test "type=uncle can paginate", %{conn: conn} do + blocks = + 51 + |> insert_list(:block) + + uncles = + for index <- 0..50 do + uncle = insert(:block, consensus: false) + insert(:block_second_degree_relation, uncle_hash: uncle.hash, nephew: Enum.at(blocks, index)) + uncle + end + + filter = %{"type" => "uncle"} + request = get(conn, "/api/v2/blocks", filter) + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/blocks", Map.merge(response["next_page_params"], filter)) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, uncles) + end + end + + describe "/blocks/{block_hash_or_number}" do + test "return 422 on invalid parameter", %{conn: conn} do + request_1 = get(conn, "/api/v2/blocks/0x123123") + assert %{"message" => "Invalid hash"} = json_response(request_1, 422) + + request_2 = get(conn, "/api/v2/blocks/123qwe") + assert %{"message" => "Invalid number"} = json_response(request_2, 422) + end + + test "return 404 on non existing block", %{conn: conn} do + block = build(:block) + + request_1 = get(conn, "/api/v2/blocks/#{block.number}") + assert %{"message" => "Not found"} = json_response(request_1, 404) + + request_2 = get(conn, "/api/v2/blocks/#{block.hash}") + assert %{"message" => "Not found"} = json_response(request_2, 404) + end + + test "get the same blocks by hash and number", %{conn: conn} do + block = insert(:block) + + request_1 = get(conn, "/api/v2/blocks/#{block.number}") + assert response_1 = json_response(request_1, 200) + + request_2 = get(conn, "/api/v2/blocks/#{block.hash}") + assert response_2 = json_response(request_2, 200) + + assert response_2 == response_1 + compare_item(block, response_2) + end + end + + describe "/blocks/{block_hash_or_number}/transactions" do + test "return 422 on invalid parameter", %{conn: conn} do + request_1 = get(conn, "/api/v2/blocks/0x123123/transactions") + assert %{"message" => "Invalid hash"} = json_response(request_1, 422) + + request_2 = get(conn, "/api/v2/blocks/123qwe/transactions") + assert %{"message" => "Invalid number"} = json_response(request_2, 422) + end + + test "return 404 on non existing block", %{conn: conn} do + block = build(:block) + + request_1 = get(conn, "/api/v2/blocks/#{block.number}/transactions") + assert %{"message" => "Not found"} = json_response(request_1, 404) + + request_2 = get(conn, "/api/v2/blocks/#{block.hash}/transactions") + assert %{"message" => "Not found"} = json_response(request_2, 404) + end + + test "get empty list", %{conn: conn} do + block = insert(:block) + + request = get(conn, "/api/v2/blocks/#{block.number}/transactions") + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + + request = get(conn, "/api/v2/blocks/#{block.hash}/transactions") + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "get relevant tx", %{conn: conn} do + 10 + |> insert_list(:transaction) + |> with_block() + + block = insert(:block) + + tx = + :transaction + |> insert() + |> with_block(block) + + request = get(conn, "/api/v2/blocks/#{block.number}/transactions") + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(tx, Enum.at(response["items"], 0)) + + request = get(conn, "/api/v2/blocks/#{block.hash}/transactions") + assert response_1 = json_response(request, 200) + assert response_1 == response + end + + test "get txs with working next_page_params", %{conn: conn} do + 2 + |> insert_list(:transaction) + |> with_block() + + block = insert(:block) + + txs = + 51 + |> insert_list(:transaction) + |> with_block(block) + |> Enum.reverse() + + request = get(conn, "/api/v2/blocks/#{block.number}/transactions") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/blocks/#{block.number}/transactions", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, txs) + + request_1 = get(conn, "/api/v2/blocks/#{block.hash}/transactions") + assert response_1 = json_response(request_1, 200) + + assert response_1 == response + + request_2 = get(conn, "/api/v2/blocks/#{block.hash}/transactions", response_1["next_page_params"]) + assert response_2 = json_response(request_2, 200) + assert response_2 == response_2nd_page + end + end + + defp compare_item(%Block{} = block, json) do + assert to_string(block.hash) == json["hash"] + assert block.number == json["height"] + end + + defp compare_item(%Transaction{} = transaction, json) do + assert to_string(transaction.hash) == json["hash"] + assert transaction.block_number == json["block"] + assert to_string(transaction.value.value) == json["value"] + assert Address.checksum(transaction.from_address_hash) == json["from"]["hash"] + assert Address.checksum(transaction.to_address_hash) == json["to"]["hash"] + end + + defp check_paginated_response(first_page_resp, second_page_resp, list) do + assert Enum.count(first_page_resp["items"]) == 50 + assert first_page_resp["next_page_params"] != nil + compare_item(Enum.at(list, 50), Enum.at(first_page_resp["items"], 0)) + compare_item(Enum.at(list, 1), Enum.at(first_page_resp["items"], 49)) + + assert Enum.count(second_page_resp["items"]) == 1 + assert second_page_resp["next_page_params"] == nil + compare_item(Enum.at(list, 0), Enum.at(second_page_resp["items"], 0)) + end +end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/config_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/config_controller_test.exs new file mode 100644 index 000000000000..0c00722d58bb --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/config_controller_test.exs @@ -0,0 +1,22 @@ +defmodule BlockScoutWeb.API.V2.ConfigControllerTest do + use BlockScoutWeb.ConnCase + + describe "/config/json-rpc-url" do + test "get json rps url if set", %{conn: conn} do + url = "http://rps.url:1234/v1" + Application.put_env(:block_scout_web, :json_rpc, url) + + request = get(conn, "/api/v2/config/json-rpc-url") + + assert %{"json_rpc_url" => ^url} = json_response(request, 200) + end + + test "get empty json rps url if not set", %{conn: conn} do + Application.put_env(:block_scout_web, :json_rpc, nil) + + request = get(conn, "/api/v2/config/json-rpc-url") + + assert %{"json_rpc_url" => nil} = json_response(request, 200) + end + end +end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs new file mode 100644 index 000000000000..75c5e2183926 --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs @@ -0,0 +1,65 @@ +defmodule BlockScoutWeb.API.V2.MainPageControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.Chain.{Address, Block, Transaction} + + setup do + Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.Blocks.child_id()) + Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.TransactionsApiV2.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.TransactionsApiV2.child_id()) + + :ok + end + + describe "/main-page/blocks" do + test "get empty list when no blocks", %{conn: conn} do + request = get(conn, "/api/v2/main-page/blocks") + assert [] = json_response(request, 200) + end + + test "get last 4 blocks", %{conn: conn} do + blocks = insert_list(10, :block) |> Enum.take(-4) |> Enum.reverse() + + request = get(conn, "/api/v2/main-page/blocks") + assert response = json_response(request, 200) + assert Enum.count(response) == 4 + + for i <- 0..3 do + compare_item(Enum.at(blocks, i), Enum.at(response, i)) + end + end + end + + describe "/main-page/transactions" do + test "get empty list when no txs", %{conn: conn} do + request = get(conn, "/api/v2/main-page/transactions") + assert [] = json_response(request, 200) + end + + test "get last 5 txs", %{conn: conn} do + txs = insert_list(10, :transaction) |> with_block() |> Enum.take(-6) |> Enum.reverse() + + request = get(conn, "/api/v2/main-page/transactions") + assert response = json_response(request, 200) + assert Enum.count(response) == 6 + + for i <- 0..5 do + compare_item(Enum.at(txs, i), Enum.at(response, i)) + end + end + end + + defp compare_item(%Block{} = block, json) do + assert to_string(block.hash) == json["hash"] + assert block.number == json["height"] + end + + defp compare_item(%Transaction{} = transaction, json) do + assert to_string(transaction.hash) == json["hash"] + assert transaction.block_number == json["block"] + assert to_string(transaction.value.value) == json["value"] + assert Address.checksum(transaction.from_address_hash) == json["from"]["hash"] + assert Address.checksum(transaction.to_address_hash) == json["to"]["hash"] + end +end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs new file mode 100644 index 000000000000..211c68dc79f0 --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs @@ -0,0 +1,147 @@ +defmodule BlockScoutWeb.API.V2.SearchControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.Chain.Address + + setup do + insert(:block) + insert(:unique_smart_contract) + insert(:unique_token) + insert(:transaction) + address = insert(:address) + insert(:unique_address_name, address: address) + + :ok + end + + describe "/search" do + test "search block", %{conn: conn} do + block = insert(:block) + + request = get(conn, "/api/v2/search?q=#{block.hash}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "block" + assert item["block_number"] == block.number + assert item["block_hash"] == to_string(block.hash) + assert item["url"] =~ to_string(block.hash) + + request = get(conn, "/api/v2/search?q=#{block.number}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "block" + assert item["block_number"] == block.number + assert item["block_hash"] == to_string(block.hash) + assert item["url"] =~ to_string(block.hash) + end + + test "search address", %{conn: conn} do + address = insert(:address) + name = insert(:unique_address_name, address: address) + + request = get(conn, "/api/v2/search?q=#{address.hash}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "address" + assert item["name"] == name.name + assert item["address"] == Address.checksum(address.hash) + assert item["url"] =~ Address.checksum(address.hash) + end + + test "search contract", %{conn: conn} do + contract = insert(:unique_smart_contract) + + request = get(conn, "/api/v2/search?q=#{contract.name}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "contract" + assert item["name"] == contract.name + assert item["address"] == Address.checksum(contract.address_hash) + assert item["url"] =~ Address.checksum(contract.address_hash) + end + + test "check pagination", %{conn: conn} do + name = "contract" + contracts = insert_list(51, :smart_contract, name: name) + + request = get(conn, "/api/v2/search?q=#{name}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "contract" + assert item["name"] == name + + request_2 = get(conn, "/api/v2/search", response["next_page_params"]) + assert response_2 = json_response(request_2, 200) + + assert Enum.count(response_2["items"]) == 1 + assert response_2["next_page_params"] == nil + + item = Enum.at(response_2["items"], 0) + + assert item["type"] == "contract" + assert item["name"] == name + + assert item not in response["items"] + end + + test "search token", %{conn: conn} do + token = insert(:unique_token) + + request = get(conn, "/api/v2/search?q=#{token.name}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "token" + assert item["name"] == token.name + assert item["symbol"] == token.symbol + assert item["address"] == Address.checksum(token.contract_address_hash) + assert item["token_url"] =~ Address.checksum(token.contract_address_hash) + assert item["address_url"] =~ Address.checksum(token.contract_address_hash) + end + + test "search transaction", %{conn: conn} do + tx = insert(:transaction) + + request = get(conn, "/api/v2/search?q=#{tx.hash}") + assert response = json_response(request, 200) + + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + + item = Enum.at(response["items"], 0) + + assert item["type"] == "transaction" + assert item["tx_hash"] == to_string(tx.hash) + assert item["url"] =~ to_string(tx.hash) + end + end +end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/stats_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/stats_controller_test.exs new file mode 100644 index 000000000000..803d5ad51ca3 --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/stats_controller_test.exs @@ -0,0 +1,57 @@ +defmodule BlockScoutWeb.API.V2.StatsControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.Counters.{AddressesCounter, AverageBlockTime} + + describe "/stats" do + setup do + start_supervised!(AddressesCounter) + start_supervised!(AverageBlockTime) + + Application.put_env(:explorer, AverageBlockTime, enabled: true) + + on_exit(fn -> + Application.put_env(:explorer, AverageBlockTime, enabled: false) + end) + + :ok + end + + test "get all fields", %{conn: conn} do + request = get(conn, "/api/v2/stats") + assert response = json_response(request, 200) + + assert Map.has_key?(response, "total_blocks") + assert Map.has_key?(response, "total_addresses") + assert Map.has_key?(response, "total_transactions") + assert Map.has_key?(response, "average_block_time") + assert Map.has_key?(response, "coin_price") + assert Map.has_key?(response, "total_gas_used") + assert Map.has_key?(response, "transactions_today") + assert Map.has_key?(response, "gas_used_today") + assert Map.has_key?(response, "gas_prices") + assert Map.has_key?(response, "static_gas_price") + assert Map.has_key?(response, "market_cap") + assert Map.has_key?(response, "network_utilization_percentage") + end + end + + describe "/stats/charts/market" do + test "get empty data", %{conn: conn} do + request = get(conn, "/api/v2/stats/charts/market") + assert response = json_response(request, 200) + + assert response["chart_data"] == [] + assert response["available_supply"] == 0 + end + end + + describe "/stats/charts/transactions" do + test "get empty data", %{conn: conn} do + request = get(conn, "/api/v2/stats/charts/transactions") + assert response = json_response(request, 200) + + assert response["chart_data"] == [] + end + end +end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/transaction_controller_test.exs new file mode 100644 index 000000000000..036b79dfc946 --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/transaction_controller_test.exs @@ -0,0 +1,582 @@ +defmodule BlockScoutWeb.API.V2.TransactionControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.Chain.{Address, InternalTransaction, Log, TokenTransfer, Transaction} + + setup do + Supervisor.terminate_child(Explorer.Supervisor, Explorer.Chain.Cache.TransactionsApiV2.child_id()) + Supervisor.restart_child(Explorer.Supervisor, Explorer.Chain.Cache.TransactionsApiV2.child_id()) + + :ok + end + + describe "/transactions" do + test "empty list", %{conn: conn} do + request = get(conn, "/api/v2/transactions") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "non empty list", %{conn: conn} do + 1 + |> insert_list(:transaction) + |> with_block() + + request = get(conn, "/api/v2/transactions") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + end + + test "txs with next_page_params", %{conn: conn} do + txs = + 51 + |> insert_list(:transaction) + |> with_block() + + request = get(conn, "/api/v2/transactions") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/transactions", response["next_page_params"]) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, txs) + end + + test "filter=pending", %{conn: conn} do + pending_txs = + 51 + |> insert_list(:transaction) + + _mined_txs = + 51 + |> insert_list(:transaction) + |> with_block() + + filter = %{"filter" => "pending"} + + request = get(conn, "/api/v2/transactions", filter) + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/transactions", Map.merge(response["next_page_params"], filter)) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, pending_txs) + end + + test "filter=validated", %{conn: conn} do + _pending_txs = + 51 + |> insert_list(:transaction) + + mined_txs = + 51 + |> insert_list(:transaction) + |> with_block() + + filter = %{"filter" => "validated"} + + request = get(conn, "/api/v2/transactions", filter) + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/transactions", Map.merge(response["next_page_params"], filter)) + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, mined_txs) + end + end + + describe "/transactions/{tx_hash}" do + test "return 404 on non existing tx", %{conn: conn} do + tx = build(:transaction) + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}") + + assert %{"message" => "Not found"} = json_response(request, 404) + end + + test "return 422 on invalid tx hash", %{conn: conn} do + request = get(conn, "/api/v2/transactions/0x") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "return existing tx", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + request = get(conn, "/api/v2/transactions/" <> to_string(tx.hash)) + + assert response = json_response(request, 200) + compare_item(tx, response) + end + end + + describe "/transactions/{tx_hash}/internal-transactions" do + test "return empty list on non existing tx", %{conn: conn} do + tx = build(:transaction) + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/internal-transactions") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "return 422 on invalid tx hash", %{conn: conn} do + request = get(conn, "/api/v2/transactions/0x/internal-transactions") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "return empty list", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/internal-transactions") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "return relevant internal transaction", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + insert(:internal_transaction, + transaction: tx, + index: 0, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: 0 + ) + + internal_tx = + insert(:internal_transaction, + transaction: tx, + index: 1, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: 1 + ) + + tx_1 = + :transaction + |> insert() + |> with_block() + + 0..5 + |> Enum.map(fn index -> + insert(:internal_transaction, + transaction: tx_1, + index: index, + block_number: tx_1.block_number, + transaction_index: tx_1.index, + block_hash: tx_1.block_hash, + block_index: index + ) + end) + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/internal-transactions") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(internal_tx, Enum.at(response["items"], 0)) + end + + test "return list with next_page_params", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + insert(:internal_transaction, + transaction: tx, + index: 0, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: 0 + ) + + internal_txs = + 51..1 + |> Enum.map(fn index -> + insert(:internal_transaction, + transaction: tx, + index: index, + block_number: tx.block_number, + transaction_index: tx.index, + block_hash: tx.block_hash, + block_index: index + ) + end) + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/internal-transactions") + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/internal-transactions", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, internal_txs) + end + end + + describe "/transactions/{tx_hash}/logs" do + test "return empty list on non existing tx", %{conn: conn} do + tx = build(:transaction) + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/logs") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "return 422 on invalid tx hash", %{conn: conn} do + request = get(conn, "/api/v2/transactions/0x/logs") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "return empty list", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/logs") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "return relevant log", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + log = + insert(:log, + transaction: tx, + index: 1, + block: tx.block, + block_number: tx.block_number + ) + + tx_1 = + :transaction + |> insert() + |> with_block() + + 0..5 + |> Enum.map(fn index -> + insert(:log, + transaction: tx_1, + index: index, + block: tx_1.block, + block_number: tx_1.block_number + ) + end) + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/logs") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(log, Enum.at(response["items"], 0)) + end + + test "return list with next_page_params", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + logs = + 50..0 + |> Enum.map(fn index -> + insert(:log, + transaction: tx, + index: index, + block: tx.block, + block_number: tx.block_number + ) + end) + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/logs") + assert response = json_response(request, 200) + + request_2nd_page = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/logs", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, logs) + end + end + + describe "/transactions/{tx_hash}/token-transfers" do + test "return empty list on non existing tx", %{conn: conn} do + tx = build(:transaction) + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "return 422 on invalid tx hash", %{conn: conn} do + request = get(conn, "/api/v2/transactions/0x/token-transfers") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "return empty list", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers") + + assert response = json_response(request, 200) + assert response["items"] == [] + assert response["next_page_params"] == nil + end + + test "return relevant token transfer", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + token_transfer = insert(:token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number) + + tx_1 = + :transaction + |> insert() + |> with_block() + + insert_list(6, :token_transfer, transaction: tx_1, block: tx_1.block, block_number: tx_1.block_number) + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers") + + assert response = json_response(request, 200) + assert Enum.count(response["items"]) == 1 + assert response["next_page_params"] == nil + compare_item(token_transfer, Enum.at(response["items"], 0)) + end + + test "return list with next_page_params", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + token_transfers = + insert_list(51, :token_transfer, transaction: tx, block: tx.block, block_number: tx.block_number) + |> Enum.reverse() + + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers") + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, token_transfers) + end + + test "check filters", %{conn: conn} do + tx = + :transaction + |> insert() + |> with_block() + + erc_1155_token = insert(:token, type: "ERC-1155") + + erc_1155_tt = + for x <- 0..50 do + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + token_contract_address: erc_1155_token.contract_address, + token_ids: [x] + ) + end + |> Enum.reverse() + + erc_721_token = insert(:token, type: "ERC-721") + + erc_721_tt = + for x <- 0..50 do + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + token_contract_address: erc_721_token.contract_address, + token_ids: [x] + ) + end + |> Enum.reverse() + + erc_20_token = insert(:token, type: "ERC-20") + + erc_20_tt = + for _ <- 0..50 do + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + token_contract_address: erc_20_token.contract_address + ) + end + |> Enum.reverse() + + # -- ERC-20 -- + filter = %{"type" => "ERC-20"} + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", + Map.merge(response["next_page_params"], filter) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_20_tt) + # -- ------ -- + + # -- ERC-721 -- + filter = %{"type" => "ERC-721"} + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", + Map.merge(response["next_page_params"], filter) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_721_tt) + # -- ------ -- + + # -- ERC-1155 -- + filter = %{"type" => "ERC-1155"} + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", + Map.merge(response["next_page_params"], filter) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, erc_1155_tt) + # -- ------ -- + + # two filters simultaneously + filter = %{"type" => "ERC-1155,ERC-20"} + request = get(conn, "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", filter) + assert response = json_response(request, 200) + + request_2nd_page = + get( + conn, + "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", + Map.merge(response["next_page_params"], filter) + ) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + assert Enum.count(response["items"]) == 50 + assert response["next_page_params"] != nil + compare_item(Enum.at(erc_1155_tt, 50), Enum.at(response["items"], 0)) + compare_item(Enum.at(erc_1155_tt, 1), Enum.at(response["items"], 49)) + + assert Enum.count(response_2nd_page["items"]) == 50 + assert response_2nd_page["next_page_params"] != nil + compare_item(Enum.at(erc_1155_tt, 0), Enum.at(response_2nd_page["items"], 0)) + compare_item(Enum.at(erc_20_tt, 50), Enum.at(response_2nd_page["items"], 1)) + compare_item(Enum.at(erc_20_tt, 2), Enum.at(response_2nd_page["items"], 49)) + + request_3rd_page = + get( + conn, + "/api/v2/transactions/#{to_string(tx.hash)}/token-transfers", + Map.merge(response_2nd_page["next_page_params"], filter) + ) + + assert response_3rd_page = json_response(request_3rd_page, 200) + assert Enum.count(response_3rd_page["items"]) == 2 + assert response_3rd_page["next_page_params"] == nil + compare_item(Enum.at(erc_20_tt, 1), Enum.at(response_3rd_page["items"], 0)) + compare_item(Enum.at(erc_20_tt, 0), Enum.at(response_3rd_page["items"], 1)) + end + end + + defp compare_item(%Transaction{} = transaction, json) do + assert to_string(transaction.hash) == json["hash"] + assert transaction.block_number == json["block"] + assert to_string(transaction.value.value) == json["value"] + assert Address.checksum(transaction.from_address_hash) == json["from"]["hash"] + assert Address.checksum(transaction.to_address_hash) == json["to"]["hash"] + end + + defp compare_item(%InternalTransaction{} = internal_tx, json) do + assert internal_tx.block_number == json["block"] + assert to_string(internal_tx.gas) == json["gas_limit"] + assert internal_tx.index == json["index"] + assert to_string(internal_tx.transaction_hash) == json["transaction_hash"] + assert Address.checksum(internal_tx.from_address_hash) == json["from"]["hash"] + assert Address.checksum(internal_tx.to_address_hash) == json["to"]["hash"] + end + + defp compare_item(%Log{} = log, json) do + assert to_string(log.data) == json["data"] + assert log.index == json["index"] + assert Address.checksum(log.address_hash) == json["address"]["hash"] + end + + defp compare_item(%TokenTransfer{} = token_transfer, json) do + assert Address.checksum(token_transfer.from_address_hash) == json["from"]["hash"] + assert Address.checksum(token_transfer.to_address_hash) == json["to"]["hash"] + assert to_string(token_transfer.transaction_hash) == json["tx_hash"] + end + + defp check_paginated_response(first_page_resp, second_page_resp, txs) do + assert Enum.count(first_page_resp["items"]) == 50 + assert first_page_resp["next_page_params"] != nil + compare_item(Enum.at(txs, 50), Enum.at(first_page_resp["items"], 0)) + compare_item(Enum.at(txs, 1), Enum.at(first_page_resp["items"], 49)) + + assert Enum.count(second_page_resp["items"]) == 1 + assert second_page_resp["next_page_params"] == nil + compare_item(Enum.at(txs, 0), Enum.at(second_page_resp["items"], 0)) + end +end diff --git a/apps/explorer/lib/explorer/application.ex b/apps/explorer/lib/explorer/application.ex index 8529ef97cf16..191840d0d363 100644 --- a/apps/explorer/lib/explorer/application.ex +++ b/apps/explorer/lib/explorer/application.ex @@ -20,6 +20,7 @@ defmodule Explorer.Application do NetVersion, Transaction, Transactions, + TransactionsApiV2, Uncles } @@ -66,6 +67,7 @@ defmodule Explorer.Application do con_cache_child_spec(MarketHistoryCache.cache_name()), con_cache_child_spec(RSK.cache_name(), ttl_check_interval: :timer.minutes(1), global_ttl: :timer.minutes(30)), Transactions, + TransactionsApiV2, Accounts, Uncles, {Redix, redix_opts()} diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 30b5c2ecd3ca..5a06bf2f553e 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -16,6 +16,7 @@ defmodule Explorer.Chain do order_by: 2, order_by: 3, preload: 2, + preload: 3, select: 2, select: 3, subquery: 1, @@ -73,6 +74,7 @@ defmodule Explorer.Chain do NewContractsCounter, NewVerifiedContractsCounter, Transactions, + TransactionsApiV2, Uncles, VerifiedContractsCounter } @@ -82,7 +84,10 @@ defmodule Explorer.Chain do alias Explorer.Counters.{ AddressesCounter, - AddressesWithBalanceCounter + AddressesWithBalanceCounter, + AddressTokenTransfersCounter, + AddressTransactionsCounter, + AddressTransactionsGasUsageCounter } alias Explorer.Market.MarketHistoryCache @@ -551,6 +556,20 @@ defmodule Explorer.Chain do |> Repo.all() end + @spec address_hash_to_token_transfers_new(Hash.Address.t() | String.t(), Keyword.t()) :: [TokenTransfer.t()] + def address_hash_to_token_transfers_new(address_hash, options \\ []) do + paging_options = Keyword.get(options, :paging_options, @default_paging_options) + direction = Keyword.get(options, :direction) + filters = Keyword.get(options, :token_type) + necessity_by_association = Keyword.get(options, :necessity_by_association) + + direction + |> TokenTransfer.token_transfers_by_address_hash(address_hash, filters) + |> join_associations(necessity_by_association) + |> TokenTransfer.handle_paging_options(paging_options) + |> Repo.all() + end + @doc """ address_hash_to_token_transfers_including_contract/2 function returns token transfers on address (to/from/contract). It is used by CSV export of token transfers button. @@ -2101,14 +2120,6 @@ defmodule Explorer.Chain do def get_token_transfers_per_transaction_preview_count, do: @token_transfers_per_transaction_preview - defp debug(value, key) do - require Logger - Logger.configure(truncate: :infinity) - Logger.info(key) - Logger.info(Kernel.inspect(value, limit: :infinity, printable_limit: :infinity)) - value - end - @doc """ Converts list of `t:Explorer.Chain.Transaction.t/0` `hashes` to the list of `t:Explorer.Chain.Transaction.t/0`s for those `hashes`. @@ -3305,19 +3316,56 @@ defmodule Explorer.Chain do the `block_number` and `index` that are passed. """ - @spec recent_collated_transactions(true | false, [paging_options | necessity_by_association_option], [String.t()], [ - :atom - ]) :: [ + @spec recent_collated_transactions(true | false, [paging_options | necessity_by_association_option]) :: [ Transaction.t() ] - def recent_collated_transactions(old_ui?, options \\ [], method_id_filter \\ [], type_filter \\ []) + def recent_collated_transactions(old_ui?, options \\ []) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = Keyword.get(options, :paging_options, @default_paging_options) + method_id_filter = Keyword.get(options, :method) + type_filter = Keyword.get(options, :type) - fetch_recent_collated_transactions(old_ui?, paging_options, necessity_by_association, method_id_filter, type_filter) + if is_nil(paging_options.key) and (method_id_filter == [] || is_nil(method_id_filter)) and + (type_filter == [] || is_nil(type_filter)) do + old_ui? + |> take_enough_from_txs_cache(paging_options.page_size) + |> case do + nil -> + transactions = + fetch_recent_collated_transactions( + old_ui?, + paging_options, + necessity_by_association, + method_id_filter, + type_filter + ) + + update_transactions_cache(old_ui?, transactions) + transactions + + transactions -> + transactions + end + else + fetch_recent_collated_transactions( + old_ui?, + paging_options, + necessity_by_association, + method_id_filter, + type_filter + ) + end end + defp take_enough_from_txs_cache(old_ui?, amount) + defp take_enough_from_txs_cache(true, amount), do: Transactions.take_enough(amount) + defp take_enough_from_txs_cache(false, amount), do: TransactionsApiV2.take_enough(amount) + + defp update_transactions_cache(old_ui?, txs) + defp update_transactions_cache(true, txs), do: Transactions.update(txs) + defp update_transactions_cache(false, txs), do: TransactionsApiV2.update(txs) + # RAP - random access pagination @spec recent_collated_transactions_for_rap([paging_options | necessity_by_association_option]) :: %{ :total_transactions_count => non_neg_integer(), @@ -3387,7 +3435,6 @@ defmodule Explorer.Chain do |> apply_filter_by_tx_type_to_transactions(type_filter) |> join_associations(necessity_by_association) |> (&if(old_ui?, do: preload(&1, [{:token_transfers, [:token, :from_address, :to_address]}]), else: &1)).() - |> debug("result collated query") |> Repo.all() |> (&if(old_ui?, do: &1, @@ -3419,13 +3466,15 @@ defmodule Explorer.Chain do Results will be the transactions older than the `inserted_at` and `hash` that are passed. """ - @spec recent_pending_transactions([paging_options | necessity_by_association_option], true | false, [String.t()], [ - :atom - ]) :: [Transaction.t()] - def recent_pending_transactions(options \\ [], old_ui? \\ true, method_id_filter \\ [], type_filter \\ []) + @spec recent_pending_transactions([paging_options | necessity_by_association_option], true | false) :: [ + Transaction.t() + ] + def recent_pending_transactions(options \\ [], old_ui? \\ true) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = Keyword.get(options, :paging_options, @default_paging_options) + method_id_filter = Keyword.get(options, :method) + type_filter = Keyword.get(options, :type) Transaction |> page_pending_transaction(paging_options) @@ -3436,7 +3485,6 @@ defmodule Explorer.Chain do |> order_by([transaction], desc: transaction.inserted_at, desc: transaction.hash) |> join_associations(necessity_by_association) |> (&if(old_ui?, do: preload(&1, [{:token_transfers, [:token, :from_address, :to_address]}]), else: &1)).() - |> debug("result pendging query") |> Repo.all() |> (&if(old_ui?, do: &1, @@ -3667,6 +3715,7 @@ defmodule Explorer.Chain do def transaction_to_token_transfers(transaction_hash, options \\ []) when is_list(options) do necessity_by_association = Keyword.get(options, :necessity_by_association, %{}) paging_options = options |> Keyword.get(:paging_options, @default_paging_options) |> Map.put(:asc_order, true) + token_type = Keyword.get(options, :token_type) TokenTransfer |> join(:inner, [token_transfer], transaction in assoc(token_transfer, :transaction)) @@ -3675,6 +3724,9 @@ defmodule Explorer.Chain do transaction.hash == ^transaction_hash and token_transfer.block_hash == transaction.block_hash and token_transfer.block_number == transaction.block_number ) + |> join(:inner, [tt], token in assoc(tt, :token), as: :token) + |> preload([token: token], [{:token, token}]) + |> TokenTransfer.filter_by_type(token_type) |> TokenTransfer.page_token_transfer(paging_options) |> limit(^paging_options.page_size) |> order_by([token_transfer], asc: token_transfer.log_index) @@ -4365,7 +4417,12 @@ defmodule Explorer.Chain do defp fetch_transactions(paging_options \\ nil, from_block \\ nil, to_block \\ nil) do Transaction - |> order_by([transaction], desc: transaction.block_number, desc: transaction.index) + |> order_by([transaction], + desc: transaction.block_number, + desc: transaction.index, + desc: transaction.inserted_at, + desc: transaction.hash + ) |> where_block_number_in_period(from_block, to_block) |> handle_paging_options(paging_options) end @@ -4578,7 +4635,10 @@ defmodule Explorer.Chain do where( query, [transaction], - transaction.inserted_at < ^inserted_at or (transaction.inserted_at == ^inserted_at and transaction.hash < ^hash) + (is_nil(transaction.block_number) and + (transaction.inserted_at < ^inserted_at or + (transaction.inserted_at == ^inserted_at and transaction.hash < ^hash))) or + not is_nil(transaction.block_number) ) end @@ -4611,6 +4671,20 @@ defmodule Explorer.Chain do defp page_search_results(query, %PagingOptions{key: nil}), do: query + defp page_search_results(query, %PagingOptions{ + key: {_address_hash, _tx_hash, _block_hash, holder_count, name, inserted_at, item_type} + }) + when holder_count in [nil, ""] do + where( + query, + [item], + (item.name > ^name and item.type == ^item_type) or + (item.name == ^name and item.inserted_at < ^inserted_at and + item.type == ^item_type) or + item.type != ^item_type + ) + end + # credo:disable-for-next-line defp page_search_results(query, %PagingOptions{ key: {_address_hash, _tx_hash, _block_hash, holder_count, name, inserted_at, item_type} @@ -6319,14 +6393,16 @@ defmodule Explorer.Chain do |> String.downcase() end - def recent_transactions(options, [:pending | _], method_id_filter, type_filter_options) do - recent_pending_transactions(options, false, method_id_filter, type_filter_options) + def recent_transactions(options, [:pending | _]) do + recent_pending_transactions(options, false) end - def recent_transactions(options, _, method_id_filter, type_filter_options) do - recent_collated_transactions(false, options, method_id_filter, type_filter_options) + def recent_transactions(options, _) do + recent_collated_transactions(false, options) end + def apply_filter_by_method_id_to_transactions(query, nil), do: query + def apply_filter_by_method_id_to_transactions(query, filter) when is_list(filter) do method_ids = Enum.flat_map(filter, &map_name_or_method_id_to_method_id/1) @@ -6537,4 +6613,53 @@ defmodule Explorer.Chain do def count_new_contracts_from_cache do NewContractsCounter.fetch() end + + def address_counters(address) do + validation_count_task = + Task.async(fn -> + address_to_validation_count(address.hash) + end) + + Task.start_link(fn -> + transaction_count(address) + end) + + Task.start_link(fn -> + token_transfers_count(address) + end) + + Task.start_link(fn -> + gas_usage_count(address) + end) + + [ + validation_count_task + ] + |> Task.yield_many(:infinity) + |> Enum.map(fn {_task, res} -> + case res do + {:ok, result} -> + result + + {:exit, reason} -> + raise "Query fetching address counters terminated: #{inspect(reason)}" + + nil -> + raise "Query fetching address counters timed out." + end + end) + |> List.to_tuple() + end + + def transaction_count(address) do + AddressTransactionsCounter.fetch(address) + end + + def token_transfers_count(address) do + AddressTokenTransfersCounter.fetch(address) + end + + def gas_usage_count(address) do + AddressTransactionsGasUsageCounter.fetch(address) + end end diff --git a/apps/explorer/lib/explorer/chain/cache/transactions_api_v2.ex b/apps/explorer/lib/explorer/chain/cache/transactions_api_v2.ex new file mode 100644 index 000000000000..0a5cf715c1bc --- /dev/null +++ b/apps/explorer/lib/explorer/chain/cache/transactions_api_v2.ex @@ -0,0 +1,27 @@ +defmodule Explorer.Chain.Cache.TransactionsApiV2 do + @moduledoc """ + Caches the latest imported transactions + """ + + alias Explorer.Chain.Transaction + + use Explorer.Chain.OrderedCache, + name: :transactions_api_v2, + max_size: 51, + preloads: [ + :block, + created_contract_address: :names, + from_address: :names, + to_address: :names + ], + ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval], + global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl] + + @type element :: Transaction.t() + + @type id :: {non_neg_integer(), non_neg_integer()} + + def element_to_id(%Transaction{block_number: block_number, index: index}) do + {block_number, index} + end +end diff --git a/apps/explorer/lib/explorer/chain/token_transfer.ex b/apps/explorer/lib/explorer/chain/token_transfer.ex index 152614b4da46..e057bdaa5166 100644 --- a/apps/explorer/lib/explorer/chain/token_transfer.ex +++ b/apps/explorer/lib/explorer/chain/token_transfer.ex @@ -25,7 +25,7 @@ defmodule Explorer.Chain.TokenTransfer do use Explorer.Schema import Ecto.Changeset - import Ecto.Query, only: [from: 2, limit: 2, where: 3] + import Ecto.Query, only: [from: 2, limit: 2, where: 3, join: 5, order_by: 3, preload: 3] alias Explorer.Chain.{Address, Block, Hash, TokenTransfer, Transaction} alias Explorer.Chain.Token.Instance @@ -241,6 +241,16 @@ defmodule Explorer.Chain.TokenTransfer do ) end + def handle_paging_options(query, nil), do: query + + def handle_paging_options(query, %PagingOptions{key: nil, page_size: nil}), do: query + + def handle_paging_options(query, paging_options) do + query + |> page_token_transfer(paging_options) + |> limit(^paging_options.page_size) + end + @doc """ Fetches the transaction hashes from token transfers according to the address hash. @@ -304,4 +314,36 @@ defmodule Explorer.Chain.TokenTransfer do tt.block_number < ^block_number ) end + + def token_transfers_by_address_hash(direction, address_hash, token_types) do + TokenTransfer + |> filter_by_direction(direction, address_hash) + |> order_by([tt], desc: tt.block_number, desc: tt.log_index) + |> join(:inner, [tt], token in assoc(tt, :token), as: :token) + |> preload([token: token], [{:token, token}]) + |> filter_by_type(token_types) + end + + def filter_by_direction(query, :to, address_hash) do + query + |> where([tt], tt.to_address_hash == ^address_hash) + end + + def filter_by_direction(query, :from, address_hash) do + query + |> where([tt], tt.from_address_hash == ^address_hash) + end + + def filter_by_direction(query, _, address_hash) do + query + |> where([tt], tt.from_address_hash == ^address_hash or tt.to_address_hash == ^address_hash) + end + + def filter_by_type(query, []), do: query + + def filter_by_type(query, token_types) when is_list(token_types) do + where(query, [token: token], token.type in ^token_types) + end + + def filter_by_type(query, _), do: query end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 892b185ac3e9..61b42a0e6002 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -3353,7 +3353,7 @@ defmodule Explorer.ChainTest do assert [ %TokenTransfer{ - token: %Ecto.Association.NotLoaded{}, + token: %Token{}, transaction: %Ecto.Association.NotLoaded{} } ] = Chain.transaction_to_token_transfers(transaction.hash) diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex index 7967d83b8d4f..7da1532025d5 100644 --- a/apps/explorer/test/support/factory.ex +++ b/apps/explorer/test/support/factory.ex @@ -170,6 +170,13 @@ defmodule Explorer.Factory do } end + def unique_address_name_factory do + %Address.Name{ + address: build(:address), + name: sequence("FooContract") + } + end + def unfetched_balance_factory do %CoinBalance{ address_hash: address_hash(), @@ -642,6 +649,10 @@ defmodule Explorer.Factory do } end + def unique_token_factory do + Map.replace(token_factory(), :name, sequence("Infinite Token")) + end + def token_transfer_log_factory do token_contract_address = build(:address) to_address = build(:address) @@ -809,6 +820,10 @@ defmodule Explorer.Factory do } end + def unique_smart_contract_factory do + Map.replace(smart_contract_factory(), :name, sequence("SimpleStorage")) + end + def decompiled_smart_contract_factory do contract_code_info = contract_code_info() @@ -839,6 +854,15 @@ defmodule Explorer.Factory do } end + def address_coin_balance_factory do + %CoinBalance{ + address: insert(:address), + block_number: insert(:block).number, + value: Enum.random(1..100_000_000), + value_fetched_at: DateTime.utc_now() + } + end + def address_current_token_balance_factory do %CurrentTokenBalance{ address: build(:address), @@ -849,6 +873,17 @@ defmodule Explorer.Factory do } end + def address_current_token_balance_with_token_id_factory do + %CurrentTokenBalance{ + address: build(:address), + token_contract_address_hash: insert(:token).contract_address_hash, + block_number: block_number(), + value: Enum.random(1..100_000), + value_fetched_at: DateTime.utc_now(), + token_id: Enum.random([nil, Enum.random(1..100_000)]) + } + end + defp block_hash_to_next_transaction_index(block_hash) do import Kernel, except: [+: 2] diff --git a/config/runtime.exs b/config/runtime.exs index d4f6f958eb9b..4f4bad6979bb 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -324,6 +324,10 @@ config :explorer, Explorer.Chain.Cache.Transactions, ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) +config :explorer, Explorer.Chain.Cache.TransactionsApiV2, + ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), + global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) + config :explorer, Explorer.Chain.Cache.Accounts, ttl_check_interval: if(disable_indexer == "true", do: :timer.seconds(1), else: false), global_ttl: if(disable_indexer == "true", do: :timer.seconds(5)) diff --git a/config/runtime/test.exs b/config/runtime/test.exs index f6ba58d424f7..ca3eed98e10c 100644 --- a/config/runtime/test.exs +++ b/config/runtime/test.exs @@ -6,6 +6,8 @@ alias EthereumJSONRPC.Variant ### BlockScout Web ### ###################### +config :block_scout_web, BlockScoutWeb.API.V2, enabled: true + ######################## ### Ethereum JSONRPC ### ######################## From 347c7314816a9d9d186a098df6ed234a0292410a Mon Sep 17 00:00:00 2001 From: Qwerty5Uiop Date: Tue, 22 Nov 2022 18:23:44 +0400 Subject: [PATCH 22/66] Remove token instance owner fetching --- CHANGELOG.md | 1 + .../lib/indexer/fetcher/token_instance.ex | 58 +------------ .../indexer/fetcher/token_instance_test.exs | 87 ------------------- 3 files changed, 3 insertions(+), 143 deletions(-) delete mode 100644 apps/indexer/test/indexer/fetcher/token_instance_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0a8a0174a7..de260db286da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ - [#6336](https://github.com/blockscout/blockscout/pull/6336) - Fix sending request on each key in token search - [#6327](https://github.com/blockscout/blockscout/pull/6327) - Fix and refactor address logs page and search - [#6449](https://github.com/blockscout/blockscout/pull/6449) - Search min_missing_block_number from zero +- [#6492](https://github.com/blockscout/blockscout/pull/6492) - Remove token instance owner fetching ### Chore diff --git a/apps/indexer/lib/indexer/fetcher/token_instance.ex b/apps/indexer/lib/indexer/fetcher/token_instance.ex index be7ac24bf5d4..2c77cadf3279 100644 --- a/apps/indexer/lib/indexer/fetcher/token_instance.ex +++ b/apps/indexer/lib/indexer/fetcher/token_instance.ex @@ -8,9 +8,8 @@ defmodule Indexer.Fetcher.TokenInstance do require Logger - alias Explorer.{Chain, Repo} - alias Explorer.Chain.{Address, Cache.BlockNumber, Token} - alias Explorer.Token.{InstanceMetadataRetriever, InstanceOwnerReader} + alias Explorer.Chain + alias Explorer.Token.InstanceMetadataRetriever alias Indexer.BufferedTask @behaviour BufferedTask @@ -53,7 +52,6 @@ defmodule Indexer.Fetcher.TokenInstance do @impl BufferedTask def run([%{contract_address_hash: hash, token_id: token_id}], _json_rpc_named_arguments) do fetch_instance(hash, token_id) - update_current_token_balances(hash, token_id) :ok end @@ -92,58 +90,6 @@ defmodule Indexer.Fetcher.TokenInstance do end end - defp update_current_token_balances(token_contract_address_hash, token_id) do - token_id - |> instance_owner_request(token_contract_address_hash) - |> List.wrap() - |> InstanceOwnerReader.get_owner_of() - |> Enum.map(¤t_token_balances_import_params/1) - |> all_import_params() - |> Chain.import() - end - - defp instance_owner_request(token_id, token_contract_address_hash) do - %{ - token_contract_address_hash: to_string(token_contract_address_hash), - token_id: Decimal.to_integer(token_id) - } - end - - defp current_token_balances_import_params(%{token_contract_address_hash: hash, token_id: token_id, owner: owner}) do - %{ - value: Decimal.new(1), - block_number: BlockNumber.get_max(), - value_fetched_at: DateTime.utc_now(), - token_id: token_id, - token_type: Repo.get_by(Token, contract_address_hash: hash).type, - address_hash: owner, - token_contract_address_hash: hash - } - end - - defp all_import_params(balances_import_params) do - addresses_import_params = - balances_import_params - |> Enum.reduce([], fn %{address_hash: address_hash}, acc -> - case Repo.get_by(Address, hash: address_hash) do - nil -> [%{hash: address_hash} | acc] - _address -> acc - end - end) - |> case do - [] -> %{} - params -> %{addresses: %{params: params}} - end - - current_token_balances_import_params = %{ - address_current_token_balances: %{ - params: balances_import_params - } - } - - Map.merge(current_token_balances_import_params, addresses_import_params) - end - @doc """ Fetches token instance data asynchronously. """ diff --git a/apps/indexer/test/indexer/fetcher/token_instance_test.exs b/apps/indexer/test/indexer/fetcher/token_instance_test.exs deleted file mode 100644 index ade5894ac5a2..000000000000 --- a/apps/indexer/test/indexer/fetcher/token_instance_test.exs +++ /dev/null @@ -1,87 +0,0 @@ -defmodule Indexer.Fetcher.TokenInstanceTest do - use EthereumJSONRPC.Case, async: false - use Explorer.DataCase - - import Mox - - alias Explorer.Chain - alias Explorer.Chain.Address - alias Explorer.Chain.Address.CurrentTokenBalance - alias Explorer.Repo - alias Indexer.Fetcher.TokenInstance - - describe "run/2" do - test "updates current token balance" do - token = insert(:token, type: "ERC-1155") - token_contract_address_hash = token.contract_address_hash - instance = insert(:token_instance, token_contract_address_hash: token_contract_address_hash) - token_id = instance.token_id - address = insert(:address, hash: "0x57e93bb58268de818b42e3795c97bad58afcd3fe") - address_hash = address.hash - - EthereumJSONRPC.Mox - |> expect(:json_rpc, fn [%{id: 0, method: "eth_call", params: [%{data: "0xc87b56dd" <> _}, _]}], _ -> - {:ok, - [ - %{ - id: 0, - result: - "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000027b7d000000000000000000000000000000000000000000000000000000000000" - } - ]} - end) - |> expect(:json_rpc, fn [%{id: 0, method: "eth_call", params: [%{data: "0x6352211e" <> _}, _]}], _ -> - {:ok, [%{id: 0, result: "0x00000000000000000000000057e93bb58268de818b42e3795c97bad58afcd3fe"}]} - end) - - TokenInstance.run( - [%{contract_address_hash: token_contract_address_hash, token_id: token_id}], - nil - ) - - assert %{ - token_id: ^token_id, - token_type: "ERC-1155", - token_contract_address_hash: ^token_contract_address_hash, - address_hash: ^address_hash - } = Repo.one(CurrentTokenBalance) - end - - test "updates current token balance with missing address" do - token = insert(:token, type: "ERC-1155") - token_contract_address_hash = token.contract_address_hash - instance = insert(:token_instance, token_contract_address_hash: token_contract_address_hash) - token_id = instance.token_id - {:ok, address_hash} = Chain.string_to_address_hash("0x57e93bb58268de818b42e3795c97bad58afcd3fe") - - EthereumJSONRPC.Mox - |> expect(:json_rpc, fn [%{id: 0, method: "eth_call", params: [%{data: "0xc87b56dd" <> _}, _]}], _ -> - {:ok, - [ - %{ - id: 0, - result: - "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000027b7d000000000000000000000000000000000000000000000000000000000000" - } - ]} - end) - |> expect(:json_rpc, fn [%{id: 0, method: "eth_call", params: [%{data: "0x6352211e" <> _}, _]}], _ -> - {:ok, [%{id: 0, result: "0x00000000000000000000000057e93bb58268de818b42e3795c97bad58afcd3fe"}]} - end) - - TokenInstance.run( - [%{contract_address_hash: token_contract_address_hash, token_id: token_id}], - nil - ) - - assert %{ - token_id: ^token_id, - token_type: "ERC-1155", - token_contract_address_hash: ^token_contract_address_hash, - address_hash: ^address_hash - } = Repo.one(CurrentTokenBalance) - - assert %Address{} = Repo.get_by(Address, hash: address_hash) - end - end -end From 039758fa9e6e9a9e4cee8eaa28d62b6d7ea4bd3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 18:22:16 +0000 Subject: [PATCH 23/66] Bump chartjs-adapter-luxon in /apps/block_scout_web/assets Bumps [chartjs-adapter-luxon](https://github.com/chartjs/chartjs-adapter-luxon) from 1.2.1 to 1.3.0. - [Release notes](https://github.com/chartjs/chartjs-adapter-luxon/releases) - [Commits](https://github.com/chartjs/chartjs-adapter-luxon/compare/v1.2.1...v1.3.0) --- updated-dependencies: - dependency-name: chartjs-adapter-luxon dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 4b034517aceb..8ee2398fc060 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -14,7 +14,7 @@ "bignumber.js": "^9.1.0", "bootstrap": "^4.6.0", "chart.js": "^4.0.1", - "chartjs-adapter-luxon": "^1.2.1", + "chartjs-adapter-luxon": "^1.3.0", "clipboard": "^2.0.11", "core-js": "^3.26.1", "crypto-browserify": "^3.12.0", @@ -5383,9 +5383,9 @@ } }, "node_modules/chartjs-adapter-luxon": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.2.1.tgz", - "integrity": "sha512-vECUr3m4IqjNyY8LZl6lbdKHmMW6+IBrn1QcaJHuuWca495y/i8N+exteYMXJktIEy8LZixwupcY3wpa315S4A==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.3.0.tgz", + "integrity": "sha512-TPqS8S7aw4a07LhFzG5DZU6Kduk1xFkaGTn8y/gfhBRvfyCkqnwFqfXqG9Gl+gmnj5DRXgPscApJUE6bsgzKjQ==", "peerDependencies": { "chart.js": ">=3.0.0", "luxon": ">=1.0.0" @@ -22466,9 +22466,9 @@ "integrity": "sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==" }, "chartjs-adapter-luxon": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.2.1.tgz", - "integrity": "sha512-vECUr3m4IqjNyY8LZl6lbdKHmMW6+IBrn1QcaJHuuWca495y/i8N+exteYMXJktIEy8LZixwupcY3wpa315S4A==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-luxon/-/chartjs-adapter-luxon-1.3.0.tgz", + "integrity": "sha512-TPqS8S7aw4a07LhFzG5DZU6Kduk1xFkaGTn8y/gfhBRvfyCkqnwFqfXqG9Gl+gmnj5DRXgPscApJUE6bsgzKjQ==", "requires": {} }, "check-error": { diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index b31097df9b43..3f5cd0293f96 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -26,7 +26,7 @@ "bignumber.js": "^9.1.0", "bootstrap": "^4.6.0", "chart.js": "^4.0.1", - "chartjs-adapter-luxon": "^1.2.1", + "chartjs-adapter-luxon": "^1.3.0", "clipboard": "^2.0.11", "core-js": "^3.26.1", "crypto-browserify": "^3.12.0", From 0be1517a9d564b3527611e027a6a77e57d0f75f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Nov 2022 18:22:48 +0000 Subject: [PATCH 24/66] Bump sweetalert2 from 11.6.10 to 11.6.13 in /apps/block_scout_web/assets Bumps [sweetalert2](https://github.com/sweetalert2/sweetalert2) from 11.6.10 to 11.6.13. - [Release notes](https://github.com/sweetalert2/sweetalert2/releases) - [Changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md) - [Commits](https://github.com/sweetalert2/sweetalert2/compare/v11.6.10...v11.6.13) --- updated-dependencies: - dependency-name: sweetalert2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 4b034517aceb..1b95e25eb2e5 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -57,7 +57,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.10", + "sweetalert2": "^11.6.13", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", @@ -16801,9 +16801,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/sweetalert2": { - "version": "11.6.10", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.10.tgz", - "integrity": "sha512-/tzEmEYqqHVkO6iMfvCFcmaO78un93CdZIhB+DGj9BLMkcuXS8jo2bmYoxjEAryhxsKPqXiWmZNo3gw/qw/ZwQ==", + "version": "11.6.13", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.13.tgz", + "integrity": "sha512-n5yVF0FNx1lm4XzpPyb1HIaiptzODfVyeCzmB809tpK+1bPdoKoevKOxYjrtId75DV7xuIp4r6cjn8xUAB8dPQ==", "funding": { "type": "individual", "url": "https://github.com/sponsors/limonte" @@ -31216,9 +31216,9 @@ } }, "sweetalert2": { - "version": "11.6.10", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.10.tgz", - "integrity": "sha512-/tzEmEYqqHVkO6iMfvCFcmaO78un93CdZIhB+DGj9BLMkcuXS8jo2bmYoxjEAryhxsKPqXiWmZNo3gw/qw/ZwQ==" + "version": "11.6.13", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.13.tgz", + "integrity": "sha512-n5yVF0FNx1lm4XzpPyb1HIaiptzODfVyeCzmB809tpK+1bPdoKoevKOxYjrtId75DV7xuIp4r6cjn8xUAB8dPQ==" }, "symbol-tree": { "version": "3.2.4", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index b31097df9b43..45083ed1cc7c 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -69,7 +69,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.10", + "sweetalert2": "^11.6.13", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", From cc4c19bee4706903d841b9081f01a19e2c19f329 Mon Sep 17 00:00:00 2001 From: sl1depengwyn Date: Thu, 17 Nov 2022 23:11:02 +0300 Subject: [PATCH 25/66] Fix state for contract creation transactions --- CHANGELOG.md | 1 + .../transaction_state_controller.ex | 18 ++++++----- .../transaction_state/_state_change.html.eex | 3 +- apps/block_scout_web/priv/gettext/default.pot | 8 ++--- .../priv/gettext/en/LC_MESSAGES/default.po | 8 ++--- .../transaction_state_controller_test.exs | 30 ++++++++++++++++++- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de260db286da..521783c3b183 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ ### Fixes +- [#6473](https://github.com/blockscout/blockscout/pull/6473) - Fix state changes for contract creation transactions - [#6475](https://github.com/blockscout/blockscout/pull/6475) - Fix token name with unicode graphemes shortening - [#6420](https://github.com/blockscout/blockscout/pull/6420) - Fix address logs search - [#6390](https://github.com/blockscout/blockscout/pull/6390) - Fix transactions responses in API v2 diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex index 4a7905d71cc8..c8e4e19feef8 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex @@ -65,11 +65,11 @@ defmodule BlockScoutWeb.TransactionStateController do to_hash = transaction.to_address_hash miner_hash = block.miner_hash - from = transaction.from_address - from_after = do_update_coin_balance_from_tx(from_hash, transaction, from_before, block) - from_coin_entry = if from_hash not in [to_hash, miner_hash] do + from = transaction.from_address + from_after = do_update_coin_balance_from_tx(from_hash, transaction, from_before, block) + View.render_to_string( TransactionStateView, "_state_change.html", @@ -83,11 +83,11 @@ defmodule BlockScoutWeb.TransactionStateController do ) end - to = transaction.to_address - to_after = do_update_coin_balance_from_tx(to_hash, transaction, to_before, block) - to_coin_entry = - if to_hash != miner_hash do + if not is_nil(to_hash) and to_hash != miner_hash do + to = transaction.to_address + to_after = do_update_coin_balance_from_tx(to_hash, transaction, to_before, block) + View.render_to_string( TransactionStateView, "_state_change.html", @@ -145,7 +145,9 @@ defmodule BlockScoutWeb.TransactionStateController do ) end - json(conn, %{items: Enum.sort([from_coin_entry, to_coin_entry, miner_entry | items])}) + json(conn, %{ + items: [from_coin_entry, to_coin_entry, miner_entry | items] |> Enum.reject(&is_nil/1) |> Enum.sort() + }) else {:restricted_access, _} -> TransactionController.set_not_found_view(conn, transaction_hash_string) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_state/_state_change.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_state/_state_change.html.eex index 180d51d9d04d..c2655c48ecf7 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_state/_state_change.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_state/_state_change.html.eex @@ -1,7 +1,6 @@ - <% coin_or_transfer = if @coin_or_token_transfers == :coin, do: :coin, else: elem(List.first(@coin_or_token_transfers), 1)%> <%= if coin_or_transfer != :coin and coin_or_transfer.token.type != "ERC-20" or has_diff?(@balance_diff) do %> - + <%= if @address.hash == @burn_address_hash do %>
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 091adcf203be..ace26ccbff2d 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -87,7 +87,7 @@ msgid "64-bit hash of value verifying proof-of-work (note: null for POA chains). msgstr "" #: lib/block_scout_web/templates/block/overview.html.eex:97 -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:23 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:22 #, elixir-autogen, elixir-format msgid "A block producer who successfully included the block onto the blockchain." msgstr "" @@ -1599,7 +1599,7 @@ msgstr "" #: lib/block_scout_web/templates/block/_tile.html.eex:41 #: lib/block_scout_web/templates/block/overview.html.eex:98 #: lib/block_scout_web/templates/chain/_block.html.eex:16 -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:24 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:23 #, elixir-autogen, elixir-format msgid "Miner" msgstr "" @@ -3272,7 +3272,7 @@ msgstr "" msgid "Library" msgstr "" -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:8 #, elixir-autogen, elixir-format msgid "Address used in token mintings and burnings." msgstr "" @@ -3287,7 +3287,7 @@ msgstr "" msgid "Balance before" msgstr "" -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:10 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 #, elixir-autogen, elixir-format msgid "Burn address" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 577368b450ac..3a9c3f463765 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -87,7 +87,7 @@ msgid "64-bit hash of value verifying proof-of-work (note: null for POA chains). msgstr "" #: lib/block_scout_web/templates/block/overview.html.eex:97 -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:23 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:22 #, elixir-autogen, elixir-format msgid "A block producer who successfully included the block onto the blockchain." msgstr "" @@ -1599,7 +1599,7 @@ msgstr "" #: lib/block_scout_web/templates/block/_tile.html.eex:41 #: lib/block_scout_web/templates/block/overview.html.eex:98 #: lib/block_scout_web/templates/chain/_block.html.eex:16 -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:24 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:23 #, elixir-autogen, elixir-format msgid "Miner" msgstr "" @@ -3272,7 +3272,7 @@ msgstr "" msgid "Library" msgstr "" -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:8 #, elixir-autogen, elixir-format msgid "Address used in token mintings and burnings." msgstr "" @@ -3287,7 +3287,7 @@ msgstr "" msgid "Balance before" msgstr "" -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:10 +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 #, elixir-autogen, elixir-format msgid "Burn address" msgstr "" diff --git a/apps/block_scout_web/test/block_scout_web/controllers/transaction_state_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/transaction_state_controller_test.exs index a4adb8f8d1e6..0090ceaa9ee1 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/transaction_state_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/transaction_state_controller_test.exs @@ -7,7 +7,6 @@ defmodule BlockScoutWeb.TransactionStateControllerTest do import BlockScoutWeb.WeiHelpers, only: [format_wei_value: 2] import EthereumJSONRPC, only: [integer_to_quantity: 1] alias Explorer.Chain.Wei - alias EthereumJSONRPC.Blocks describe "GET index/3" do test "loads existing transaction", %{conn: conn} do @@ -50,6 +49,35 @@ defmodule BlockScoutWeb.TransactionStateControllerTest do assert(items |> Enum.filter(fn item -> item != nil end) |> length() == 1) end + test "returns state changes for the transaction with contract creation", %{conn: conn} do + block = insert(:block) + + contract_address = insert(:contract_address) + + transaction = + :transaction + |> insert(to_address: nil) + |> with_contract_creation(contract_address) + |> with_block(insert(:block)) + + insert(:fetched_balance, + address_hash: transaction.from_address_hash, + value: 1_000_000, + block_number: block.number + ) + + insert(:fetched_balance, + address_hash: transaction.block.miner_hash, + value: 1_000_000, + block_number: block.number + ) + + conn = get(conn, transaction_state_path(conn, :index, transaction), %{type: "JSON"}) + {:ok, %{"items" => items}} = conn.resp_body |> Poison.decode() + + assert(items |> Enum.filter(fn item -> item != nil end) |> length() == 2) + end + test "returns fetched state changes for the transaction with token transfer", %{conn: conn} do block = insert(:block) address_a = insert(:address) From 102d9a338065b51c1eeb8e3e1c8a77202e6bd024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Thu, 24 Nov 2022 19:04:15 +0300 Subject: [PATCH 26/66] Remove caching for api v2 txs --- apps/explorer/lib/explorer/chain.ex | 46 +++++------------------------ 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 5a06bf2f553e..2ccb300b3e3e 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -74,7 +74,6 @@ defmodule Explorer.Chain do NewContractsCounter, NewVerifiedContractsCounter, Transactions, - TransactionsApiV2, Uncles, VerifiedContractsCounter } @@ -3326,46 +3325,15 @@ defmodule Explorer.Chain do method_id_filter = Keyword.get(options, :method) type_filter = Keyword.get(options, :type) - if is_nil(paging_options.key) and (method_id_filter == [] || is_nil(method_id_filter)) and - (type_filter == [] || is_nil(type_filter)) do - old_ui? - |> take_enough_from_txs_cache(paging_options.page_size) - |> case do - nil -> - transactions = - fetch_recent_collated_transactions( - old_ui?, - paging_options, - necessity_by_association, - method_id_filter, - type_filter - ) - - update_transactions_cache(old_ui?, transactions) - transactions - - transactions -> - transactions - end - else - fetch_recent_collated_transactions( - old_ui?, - paging_options, - necessity_by_association, - method_id_filter, - type_filter - ) - end + fetch_recent_collated_transactions( + old_ui?, + paging_options, + necessity_by_association, + method_id_filter, + type_filter + ) end - defp take_enough_from_txs_cache(old_ui?, amount) - defp take_enough_from_txs_cache(true, amount), do: Transactions.take_enough(amount) - defp take_enough_from_txs_cache(false, amount), do: TransactionsApiV2.take_enough(amount) - - defp update_transactions_cache(old_ui?, txs) - defp update_transactions_cache(true, txs), do: Transactions.update(txs) - defp update_transactions_cache(false, txs), do: TransactionsApiV2.update(txs) - # RAP - random access pagination @spec recent_collated_transactions_for_rap([paging_options | necessity_by_association_option]) :: %{ :total_transactions_count => non_neg_integer(), From a1643613278938743a618f4769f37468c42a3974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Thu, 24 Nov 2022 19:07:05 +0300 Subject: [PATCH 27/66] Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de260db286da..a32d0d77b255 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ - [#6475](https://github.com/blockscout/blockscout/pull/6475) - Fix token name with unicode graphemes shortening - [#6420](https://github.com/blockscout/blockscout/pull/6420) - Fix address logs search -- [#6390](https://github.com/blockscout/blockscout/pull/6390) - Fix transactions responses in API v2 +- [#6390](https://github.com/blockscout/blockscout/pull/6390), [#6502](https://github.com/blockscout/blockscout/pull/6502) - Fix transactions responses in API v2 - [#6357](https://github.com/blockscout/blockscout/pull/6357), [#6409](https://github.com/blockscout/blockscout/pull/6409), [#6428](https://github.com/blockscout/blockscout/pull/6428) - Fix definitions of NETWORK_PATH, API_PATH, SOCKET_ROOT: process trailing slash - [#6338](https://github.com/blockscout/blockscout/pull/6338) - Fix token search with space - [#6329](https://github.com/blockscout/blockscout/pull/6329) - Prevent logger from truncating response from rust verifier service in case of an error From f13221f2994c993b2618f27a9cc87e94fd754618 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Nov 2022 18:10:12 +0000 Subject: [PATCH 28/66] Bump sweetalert2 from 11.6.13 to 11.6.14 in /apps/block_scout_web/assets Bumps [sweetalert2](https://github.com/sweetalert2/sweetalert2) from 11.6.13 to 11.6.14. - [Release notes](https://github.com/sweetalert2/sweetalert2/releases) - [Changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md) - [Commits](https://github.com/sweetalert2/sweetalert2/compare/v11.6.13...v11.6.14) --- updated-dependencies: - dependency-name: sweetalert2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 1b95e25eb2e5..6f0f7cc187c0 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -57,7 +57,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.13", + "sweetalert2": "^11.6.14", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", @@ -16801,9 +16801,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/sweetalert2": { - "version": "11.6.13", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.13.tgz", - "integrity": "sha512-n5yVF0FNx1lm4XzpPyb1HIaiptzODfVyeCzmB809tpK+1bPdoKoevKOxYjrtId75DV7xuIp4r6cjn8xUAB8dPQ==", + "version": "11.6.14", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.14.tgz", + "integrity": "sha512-W8+vtsucIJg5BrFhHcqguNZMzmHGvVZVAYHaMGQ9dzrleOMZcHCGmnB46L9qUNdx5snr1GpMUVFjNuki7EBbuQ==", "funding": { "type": "individual", "url": "https://github.com/sponsors/limonte" @@ -31216,9 +31216,9 @@ } }, "sweetalert2": { - "version": "11.6.13", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.13.tgz", - "integrity": "sha512-n5yVF0FNx1lm4XzpPyb1HIaiptzODfVyeCzmB809tpK+1bPdoKoevKOxYjrtId75DV7xuIp4r6cjn8xUAB8dPQ==" + "version": "11.6.14", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.14.tgz", + "integrity": "sha512-W8+vtsucIJg5BrFhHcqguNZMzmHGvVZVAYHaMGQ9dzrleOMZcHCGmnB46L9qUNdx5snr1GpMUVFjNuki7EBbuQ==" }, "symbol-tree": { "version": "3.2.4", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 45083ed1cc7c..bd7ecad2c8f1 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -69,7 +69,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.13", + "sweetalert2": "^11.6.14", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", From eb50efa70276a9aad881f49f30dfb6444faad838 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Nov 2022 18:10:37 +0000 Subject: [PATCH 29/66] Bump highlight.js from 11.6.0 to 11.7.0 in /apps/block_scout_web/assets Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 11.6.0 to 11.7.0. - [Release notes](https://github.com/highlightjs/highlight.js/releases) - [Changelog](https://github.com/highlightjs/highlight.js/blob/main/CHANGES.md) - [Commits](https://github.com/highlightjs/highlight.js/compare/11.6.0...11.7.0) --- updated-dependencies: - dependency-name: highlight.js dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 1b95e25eb2e5..cc2eba5a6dad 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -20,7 +20,7 @@ "crypto-browserify": "^3.12.0", "dropzone": "^5.9.3", "eth-net-props": "^1.0.41", - "highlight.js": "^11.6.0", + "highlight.js": "^11.7.0", "https-browserify": "^1.0.0", "humps": "^2.0.1", "jquery": "^3.6.1", @@ -9295,9 +9295,9 @@ } }, "node_modules/highlight.js": { - "version": "11.6.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.6.0.tgz", - "integrity": "sha512-ig1eqDzJaB0pqEvlPVIpSSyMaO92bH1N2rJpLMN/nX396wTpDA4Eq0uK+7I/2XG17pFaaKE0kjV/XPeGt7Evjw==", + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz", + "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==", "engines": { "node": ">=12.0.0" } @@ -25541,9 +25541,9 @@ } }, "highlight.js": { - "version": "11.6.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.6.0.tgz", - "integrity": "sha512-ig1eqDzJaB0pqEvlPVIpSSyMaO92bH1N2rJpLMN/nX396wTpDA4Eq0uK+7I/2XG17pFaaKE0kjV/XPeGt7Evjw==" + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz", + "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==" }, "hmac-drbg": { "version": "1.0.1", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 45083ed1cc7c..6a7db0d67b03 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -32,7 +32,7 @@ "crypto-browserify": "^3.12.0", "dropzone": "^5.9.3", "eth-net-props": "^1.0.41", - "highlight.js": "^11.6.0", + "highlight.js": "^11.7.0", "https-browserify": "^1.0.0", "humps": "^2.0.1", "jquery": "^3.6.1", From febb5d09ea5f92c486af2d5410e5288cf7d95b2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Nov 2022 18:11:00 +0000 Subject: [PATCH 30/66] Bump web3modal from 1.9.9 to 1.9.10 in /apps/block_scout_web/assets Bumps [web3modal](https://github.com/web3modal/web3modal) from 1.9.9 to 1.9.10. - [Release notes](https://github.com/web3modal/web3modal/releases) - [Commits](https://github.com/web3modal/web3modal/commits) --- updated-dependencies: - dependency-name: web3modal dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 1b95e25eb2e5..d96664160328 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -62,7 +62,7 @@ "url": "^0.11.0", "util": "^0.12.5", "web3": "^1.8.1", - "web3modal": "^1.9.9", + "web3modal": "^1.9.10", "xss": "^1.0.14" }, "devDependencies": { @@ -17929,9 +17929,9 @@ } }, "node_modules/web3modal": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/web3modal/-/web3modal-1.9.9.tgz", - "integrity": "sha512-ML1C4xH+JTSHHkKbjxuF+f5B3cDUOCnrdQZ8Mlzippq7zRKHf3NBeuIvDdNjtVclJ2S4zYYVmVqRWrgB11ej8A==", + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/web3modal/-/web3modal-1.9.10.tgz", + "integrity": "sha512-gRByp+toRiADwkJLLGRXsnIVbLS1aJB71sJyryS6C7cF6jJ3cRN1LbPYEMObMyJkyjOZonx0CNZVAYGiD099aA==", "dependencies": { "detect-browser": "^5.1.0", "prop-types": "^15.7.2", @@ -32141,9 +32141,9 @@ } }, "web3modal": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/web3modal/-/web3modal-1.9.9.tgz", - "integrity": "sha512-ML1C4xH+JTSHHkKbjxuF+f5B3cDUOCnrdQZ8Mlzippq7zRKHf3NBeuIvDdNjtVclJ2S4zYYVmVqRWrgB11ej8A==", + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/web3modal/-/web3modal-1.9.10.tgz", + "integrity": "sha512-gRByp+toRiADwkJLLGRXsnIVbLS1aJB71sJyryS6C7cF6jJ3cRN1LbPYEMObMyJkyjOZonx0CNZVAYGiD099aA==", "requires": { "detect-browser": "^5.1.0", "prop-types": "^15.7.2", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 45083ed1cc7c..f3e3f69c803e 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -74,7 +74,7 @@ "url": "^0.11.0", "util": "^0.12.5", "web3": "^1.8.1", - "web3modal": "^1.9.9", + "web3modal": "^1.9.10", "xss": "^1.0.14" }, "devDependencies": { From aae90a3bd25f7c482dac4b45bbf23a84a93ee37d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Nov 2022 18:11:42 +0000 Subject: [PATCH 31/66] Bump remote_ip from 1.0.0 to 1.1.0 Bumps [remote_ip](https://github.com/ajvondrak/remote_ip) from 1.0.0 to 1.1.0. - [Release notes](https://github.com/ajvondrak/remote_ip/releases) - [Commits](https://github.com/ajvondrak/remote_ip/compare/v1.0.0...v1.1.0) --- updated-dependencies: - dependency-name: remote_ip dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- mix.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.lock b/mix.lock index 71ced4066a1f..46186a271b12 100644 --- a/mix.lock +++ b/mix.lock @@ -117,7 +117,7 @@ "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ratio": {:hex, :ratio, "2.4.2", "c8518f3536d49b1b00d88dd20d49f8b11abb7819638093314a6348139f14f9f9", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "441ef6f73172a3503de65ccf1769030997b0d533b1039422f1e5e0e0b4cbf89e"}, "redix": {:hex, :redix, "1.2.0", "0d7eb3ccb7b82c461a6ea28b65c2c04486093d816dd6d901a09164800e004df1", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e1e0deb14599da07c77e66956a12863e85ee270ada826804a0ba8e61657e22a3"}, - "remote_ip": {:hex, :remote_ip, "1.0.0", "3d7fb45204a5704443f480cee9515e464997f52c35e0a60b6ece1f81484067ae", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9e9fcad4e50c43b5234bb6a9629ed6ab223f3ed07147bd35470e4ee5c8caf907"}, + "remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"}, "rustler": {:hex, :rustler, "0.26.0", "06a2773d453ee3e9109efda643cf2ae633dedea709e2455ac42b83637c9249bf", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "42961e9d2083d004d5a53e111ad1f0c347efd9a05cb2eb2ffa1d037cdc74db91"}, "sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"}, "spandex": {:hex, :spandex, "3.2.0", "f8cd40146ea988c87f3c14054150c9a47ba17e53cd4515c00e1f93c29c45404d", [:mix], [{:decorator, "~> 1.2", [hex: :decorator, repo: "hexpm", optional: true]}, {:optimal, "~> 0.3.3", [hex: :optimal, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d0a7d5aef4c5af9cf5467f2003e8a5d8d2bdae3823a6cc95d776b9a2251d4d03"}, From 9bcdea82049a6bad75b9986c00c5ecfd47bcf6da Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Sun, 6 Nov 2022 19:14:12 +0300 Subject: [PATCH 32/66] Add visualuze sol2uml controller --- .../visualize_sol2uml_controller.ex | 41 ++++++++++ .../templates/address_contract/index.html.eex | 22 ++++-- .../visualize_sol2uml/index.html.eex | 16 ++++ .../views/visualize_sol2uml_view.ex | 3 + .../lib/block_scout_web/web_router.ex | 2 + .../lib/explorer/visualize/sol2uml.ex | 74 +++++++++++++++++++ config/runtime.exs | 4 + 7 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex create mode 100644 apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex create mode 100644 apps/block_scout_web/lib/block_scout_web/views/visualize_sol2uml_view.ex create mode 100644 apps/explorer/lib/explorer/visualize/sol2uml.ex diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex new file mode 100644 index 000000000000..3c22cd96c7d5 --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex @@ -0,0 +1,41 @@ +defmodule BlockScoutWeb.VisualizeSol2umlController do + use BlockScoutWeb, :controller + alias Explorer.Chain + alias Explorer.Visualize.Sol2uml + + def index(conn, %{"address" => address_hash_string}) do + address_options = [ + necessity_by_association: %{ + :contracts_creation_internal_transaction => :optional, + :names => :optional, + :smart_contract => :optional, + :token => :optional, + :contracts_creation_transaction => :optional + } + ] + with true <- Sol2uml.enabled?(), + true <- Chain.smart_contract_fully_verified?(address_hash_string), + {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), + {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do + sources = address.smart_contract_additional_sources + |> Enum.map(fn (additional_source) -> {additional_source.file_name, additional_source.contract_source_code} end) + |> Enum.into(%{}) + |> Map.merge(%{ + address.smart_contract.file_path => address.smart_contract.contract_source_code + }) + params = %{ + sources: sources + } + case Sol2uml.visualize_contracts(params) do + {:ok, svg} -> render(conn, "index.html", address: address, svg: svg, error: nil) + {:error, error} -> render(conn, "index.html", address: address, svg: nil, error: error) + end + else + _ -> not_found(conn) + end + end + + def index(conn, params) do + not_found(conn) + end +end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index a5956a5dcadf..cd898026ea39 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -5,6 +5,7 @@ <% additional_sources_from_twin = Chain.get_address_verified_twin_contract(@address.hash).additional_sources %> <% fully_verified = Chain.smart_contract_fully_verified?(@address.hash)%> <% additional_sources = if smart_contract_verified, do: @address.smart_contract_additional_sources, else: additional_sources_from_twin %> +<% visualize_sol2uml_enabled = Explorer.Visualize.Sol2uml.enabled?() %>
<% is_proxy = BlockScoutWeb.AddressView.smart_contract_is_proxy?(@address) %> @@ -23,7 +24,7 @@
<%= render BlockScoutWeb.CommonComponentsView, "_info.html" %> <%= gettext("Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB") %> <%= link( - metadata_for_verification.address_hash, + metadata_for_verification.address_hash, to: address_contract_path(@conn, :index, metadata_for_verification.address_hash)) %>.
<%= gettext("All metadata displayed below is from that contract. In order to verify current contract, click") %> <%= gettext("Verify & Publish") %> <%= gettext("button") %>
<%= link(gettext("Verify & Publish"), to: path, class: "button button-primary button-sm float-right ml-3", "data-test": "verify_and_publish") %> @@ -98,9 +99,20 @@

<%= target_contract.file_path || gettext "Contract source code" %>

- +
+ <%= if visualize_sol2uml_enabled do %> + +
+
new
+ + Sol2uml +
+
+ <% end %> + +
><%= target_contract.contract_source_code %>
         
@@ -171,7 +183,7 @@
<%= creation_code(@address) %>
- <% end %> + <% end %> <%= if fully_verified do %>

<%= gettext "Deployed ByteCode" %>

diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex new file mode 100644 index 000000000000..f0d25512694e --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex @@ -0,0 +1,16 @@ +
+
+
+
+

<%= gettext("UML diagram") %>

+ <%= gettext("For contract") %> <%= link( + @address.hash, + to: address_contract_path(@conn, :index, @address.hash) + ) %> +
+
+ +
+
+
+
diff --git a/apps/block_scout_web/lib/block_scout_web/views/visualize_sol2uml_view.ex b/apps/block_scout_web/lib/block_scout_web/views/visualize_sol2uml_view.ex new file mode 100644 index 000000000000..827deeeecdec --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/views/visualize_sol2uml_view.ex @@ -0,0 +1,3 @@ +defmodule BlockScoutWeb.VisualizeSol2umlView do + use BlockScoutWeb, :view +end diff --git a/apps/block_scout_web/lib/block_scout_web/web_router.ex b/apps/block_scout_web/lib/block_scout_web/web_router.ex index e03bd10d43ba..c356489ff189 100644 --- a/apps/block_scout_web/lib/block_scout_web/web_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/web_router.ex @@ -494,6 +494,8 @@ defmodule BlockScoutWeb.WebRouter do get("/token-counters", Tokens.TokenController, :token_counters) + get("/vis/sol2uml", VisualizeSol2umlController, :index) + get("/*path", PageNotFoundController, :index) end end diff --git a/apps/explorer/lib/explorer/visualize/sol2uml.ex b/apps/explorer/lib/explorer/visualize/sol2uml.ex new file mode 100644 index 000000000000..d54f6c368146 --- /dev/null +++ b/apps/explorer/lib/explorer/visualize/sol2uml.ex @@ -0,0 +1,74 @@ +defmodule Explorer.Visualize.Sol2uml do + @moduledoc """ + Adapter for sol2uml visualizer with https://github.com/blockscout/blockscout-rs/blob/main/visualizer + """ + alias HTTPoison.Response + require Logger + + @post_timeout :infinity + @request_error_msg "Error while sending request to visualizer microservice" + + def visualize_contracts(body) do + http_post_request(visualize_contracts_url(), body) + end + + def http_post_request(url, body) do + headers = [{"Content-Type", "application/json"}] + + case HTTPoison.post(url, Jason.encode!(body), headers, recv_timeout: @post_timeout) do + {:ok, %Response{body: body, status_code: 200}} -> + proccess_visualizer_response(body) + + {:ok, %Response{body: body, status_code: _}} -> + proccess_visualizer_response(body) + + {:error, error} -> + old_truncate = Application.get_env(:logger, :truncate) + Logger.configure(truncate: :infinity) + + Logger.error(fn -> + [ + "Error while sending request to visualizer microservice. url: #{url}, body: #{inspect(body, limit: :infinity, printable_limit: :infinity)}: ", + inspect(error, limit: :infinity, printable_limit: :infinity) + ] + end) + + Logger.configure(truncate: old_truncate) + {:error, @request_error_msg} + end + end + + + def proccess_visualizer_response(body) when is_binary(body) do + case Jason.decode(body) do + {:ok, decoded} -> + proccess_visualizer_response(decoded) + + _ -> + {:error, body} + end + end + + def proccess_visualizer_response(%{"svg" => svg}) do + {:ok, svg} + end + + def proccess_visualizer_response(other), do: {:error, other} + + def visualize_contracts_url, do: "#{base_api_url()}" <> "/solidity:visualizeContracts" + + def base_api_url, do: "#{base_url()}" <> "/api/v1" + + def base_url do + url = Application.get_env(:explorer, __MODULE__)[:service_url] + + if String.ends_with?(url, "/") do + url + |> String.slice(0..(String.length(url) - 2)) + else + url + end + end + + def enabled?, do: Application.get_env(:explorer, __MODULE__)[:enabled] +end diff --git a/config/runtime.exs b/config/runtime.exs index 4f4bad6979bb..d3b31abf7e25 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -215,6 +215,10 @@ config :explorer, else: Explorer.Chain.Events.DBSender ) +config :explorer, Explorer.Visualize.Sol2uml, + service_url: System.get_env("VISUALIZE_SOL2UML_SERVICE_URL"), + enabled: System.get_env("VISUALIZE_SOL2UML_ENABLED") == "true" + config :explorer, Explorer.Chain.Events.Listener, enabled: if(disable_webapp == "true" && disable_indexer == "true", From 7957179a2230fbc7d1c161cf46b851c3189b0d03 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Sun, 6 Nov 2022 19:21:41 +0300 Subject: [PATCH 33/66] Mix format --- .../visualize_sol2uml_controller.ex | 30 +++++++++++-------- .../lib/explorer/visualize/sol2uml.ex | 1 - 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex index 3c22cd96c7d5..d56cd89acdb1 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex @@ -13,23 +13,27 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do :contracts_creation_transaction => :optional } ] + with true <- Sol2uml.enabled?(), true <- Chain.smart_contract_fully_verified?(address_hash_string), {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do - sources = address.smart_contract_additional_sources - |> Enum.map(fn (additional_source) -> {additional_source.file_name, additional_source.contract_source_code} end) - |> Enum.into(%{}) - |> Map.merge(%{ - address.smart_contract.file_path => address.smart_contract.contract_source_code - }) - params = %{ - sources: sources - } - case Sol2uml.visualize_contracts(params) do - {:ok, svg} -> render(conn, "index.html", address: address, svg: svg, error: nil) - {:error, error} -> render(conn, "index.html", address: address, svg: nil, error: error) - end + sources = + address.smart_contract_additional_sources + |> Enum.map(fn additional_source -> {additional_source.file_name, additional_source.contract_source_code} end) + |> Enum.into(%{}) + |> Map.merge(%{ + address.smart_contract.file_path => address.smart_contract.contract_source_code + }) + + params = %{ + sources: sources + } + + case Sol2uml.visualize_contracts(params) do + {:ok, svg} -> render(conn, "index.html", address: address, svg: svg, error: nil) + {:error, error} -> render(conn, "index.html", address: address, svg: nil, error: error) + end else _ -> not_found(conn) end diff --git a/apps/explorer/lib/explorer/visualize/sol2uml.ex b/apps/explorer/lib/explorer/visualize/sol2uml.ex index d54f6c368146..879bf9ec54f4 100644 --- a/apps/explorer/lib/explorer/visualize/sol2uml.ex +++ b/apps/explorer/lib/explorer/visualize/sol2uml.ex @@ -38,7 +38,6 @@ defmodule Explorer.Visualize.Sol2uml do end end - def proccess_visualizer_response(body) when is_binary(body) do case Jason.decode(body) do {:ok, decoded} -> From e69295ed5cf77b32c9fa6eb49c09ab34cb825464 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Mon, 7 Nov 2022 18:48:00 +0300 Subject: [PATCH 34/66] Add image viewer --- .../assets/js/pages/img_viewer.js | 3 ++ apps/block_scout_web/assets/package-lock.json | 32 +++++++++++++++++-- apps/block_scout_web/assets/package.json | 2 ++ apps/block_scout_web/assets/webpack.config.js | 1 + .../templates/address_contract/index.html.eex | 18 +++++------ .../visualize_sol2uml/index.html.eex | 7 +++- 6 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 apps/block_scout_web/assets/js/pages/img_viewer.js diff --git a/apps/block_scout_web/assets/js/pages/img_viewer.js b/apps/block_scout_web/assets/js/pages/img_viewer.js new file mode 100644 index 000000000000..544443d68518 --- /dev/null +++ b/apps/block_scout_web/assets/js/pages/img_viewer.js @@ -0,0 +1,3 @@ +import Viewer from 'viewerjs' +const gallery = document.getElementById('img-view') +const viewer = new Viewer(gallery) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index dc39a7ef37dd..4ed35918d294 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -24,6 +24,7 @@ "https-browserify": "^1.0.0", "humps": "^2.0.1", "jquery": "^3.6.1", + "jquery-viewer": "^1.0.1", "js-cookie": "^3.0.1", "lodash.debounce": "^4.0.8", "lodash.differenceby": "^4.8.0", @@ -61,6 +62,7 @@ "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", + "viewerjs": "^1.11.1", "web3": "^1.8.1", "web3modal": "^1.9.10", "xss": "^1.0.14" @@ -96,10 +98,11 @@ } }, "../../../deps/phoenix": { - "version": "0.0.1" + "version": "1.5.13", + "license": "MIT" }, "../../../deps/phoenix_html": { - "version": "0.0.1" + "version": "3.0.4" }, "node_modules/@ampproject/remapping": { "version": "2.2.0", @@ -11888,6 +11891,15 @@ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" }, + "node_modules/jquery-viewer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jquery-viewer/-/jquery-viewer-1.0.1.tgz", + "integrity": "sha512-d7qd/9zKCcsxgKDDt9nC2Jdbr2SdXcJkQVzQDxj/H7ZkXzS+scxt2KxGWQlsBthiRmvv9aCPt7kPnGsFA2ds/Q==", + "peerDependencies": { + "jquery": ">=1.9.1", + "viewerjs": ">=1.5.0" + } + }, "node_modules/js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -17428,6 +17440,11 @@ "extsprintf": "^1.2.0" } }, + "node_modules/viewerjs": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.1.tgz", + "integrity": "sha512-/VQ2zalHLZJOGIwlxOBtxagLZwNvU3Bf+nm692XlhNFxjBXRxpCVn+GeqmRFg9jK1Y2+Wf8PPGxZgTDN4pHXww==" + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -27449,6 +27466,12 @@ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" }, + "jquery-viewer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jquery-viewer/-/jquery-viewer-1.0.1.tgz", + "integrity": "sha512-d7qd/9zKCcsxgKDDt9nC2Jdbr2SdXcJkQVzQDxj/H7ZkXzS+scxt2KxGWQlsBthiRmvv9aCPt7kPnGsFA2ds/Q==", + "requires": {} + }, "js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -31701,6 +31724,11 @@ "extsprintf": "^1.2.0" } }, + "viewerjs": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.1.tgz", + "integrity": "sha512-/VQ2zalHLZJOGIwlxOBtxagLZwNvU3Bf+nm692XlhNFxjBXRxpCVn+GeqmRFg9jK1Y2+Wf8PPGxZgTDN4pHXww==" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index f283833a8b2a..eb004a2a9020 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -36,6 +36,7 @@ "https-browserify": "^1.0.0", "humps": "^2.0.1", "jquery": "^3.6.1", + "jquery-viewer": "^1.0.1", "js-cookie": "^3.0.1", "lodash.debounce": "^4.0.8", "lodash.differenceby": "^4.8.0", @@ -75,6 +76,7 @@ "util": "^0.12.5", "web3": "^1.8.1", "web3modal": "^1.9.10", + "viewerjs": "^1.11.1", "xss": "^1.0.14" }, "devDependencies": { diff --git a/apps/block_scout_web/assets/webpack.config.js b/apps/block_scout_web/assets/webpack.config.js index 0a1ec272fb72..29bce00a6aaf 100644 --- a/apps/block_scout_web/assets/webpack.config.js +++ b/apps/block_scout_web/assets/webpack.config.js @@ -57,6 +57,7 @@ const appJs = 'admin-tasks': './js/pages/admin/tasks.js', 'token-contract': './js/pages/token_contract.js', 'smart-contract-helpers': './js/lib/smart_contract/index.js', + 'img_viewer': './js/pages/img_viewer.js', 'token-transfers-toggle': './js/lib/token_transfers_toggle.js', 'try-api': './js/lib/try_api.js', 'try-eth-api': './js/lib/try_eth_api.js', diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index cd898026ea39..a40d43ea276b 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -100,16 +100,16 @@

<%= target_contract.file_path || gettext "Contract source code" %>

- <%= if visualize_sol2uml_enabled do %> - -
-
new
- - Sol2uml -
-
+ <%= if visualize_sol2uml_enabled && !target_contract.is_vyper_contract do %> + + +
new
+ + Sol2uml +
+
<% end %> -
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex index f0d25512694e..e60c6f216fb3 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex @@ -8,9 +8,14 @@ to: address_contract_path(@conn, :index, @address.hash) ) %>
+ <%= if is_nil(@error) do %>
- +
+ <% else %> + <%= gettext("Cannot visualize contract")%>: <%= @error %> + <% end %>
+ From d405a672d53a760ecf32b554202e24367356491e Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 8 Nov 2022 12:32:28 +0300 Subject: [PATCH 35/66] Fix image viewer bug --- .../assets/js/pages/img_viewer.js | 23 ++++++++++-- apps/block_scout_web/assets/package-lock.json | 37 +++++++++---------- apps/block_scout_web/assets/package.json | 3 +- apps/block_scout_web/assets/webpack.config.js | 4 ++ .../visualize_sol2uml/index.html.eex | 4 +- 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/apps/block_scout_web/assets/js/pages/img_viewer.js b/apps/block_scout_web/assets/js/pages/img_viewer.js index 544443d68518..9b9e26749d47 100644 --- a/apps/block_scout_web/assets/js/pages/img_viewer.js +++ b/apps/block_scout_web/assets/js/pages/img_viewer.js @@ -1,3 +1,20 @@ -import Viewer from 'viewerjs' -const gallery = document.getElementById('img-view') -const viewer = new Viewer(gallery) +import 'viewerjs/dist/viewer.min.css'; +import Viewer from 'viewerjs'; +const gallery = document.getElementById('gallery'); +const viewer = new Viewer(gallery, { + inline: false, + toolbar: { + zoomIn: 2, + zoomOut: 4, + oneToOne: 4, + reset: 4, + play: { + show: 4, + size: 'large', + }, + rotateLeft: 4, + rotateRight: 4, + flipHorizontal: 4, + flipVertical: 4, + } +}); diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 4ed35918d294..24bc901f47ef 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -23,8 +23,6 @@ "highlight.js": "^11.7.0", "https-browserify": "^1.0.0", "humps": "^2.0.1", - "jquery": "^3.6.1", - "jquery-viewer": "^1.0.1", "js-cookie": "^3.0.1", "lodash.debounce": "^4.0.8", "lodash.differenceby": "^4.8.0", @@ -52,6 +50,7 @@ "path-parser": "^6.1.0", "phoenix": "file:../../../deps/phoenix", "phoenix_html": "file:../../../deps/phoenix_html", + "photoswipe": "^5.3.3", "pikaday": "^1.8.2", "popper.js": "^1.14.7", "reduce-reducers": "^1.0.4", @@ -11889,16 +11888,8 @@ "node_modules/jquery": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" - }, - "node_modules/jquery-viewer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jquery-viewer/-/jquery-viewer-1.0.1.tgz", - "integrity": "sha512-d7qd/9zKCcsxgKDDt9nC2Jdbr2SdXcJkQVzQDxj/H7ZkXzS+scxt2KxGWQlsBthiRmvv9aCPt7kPnGsFA2ds/Q==", - "peerDependencies": { - "jquery": ">=1.9.1", - "viewerjs": ">=1.5.0" - } + "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==", + "peer": true }, "node_modules/js-base64": { "version": "2.6.4", @@ -14036,6 +14027,14 @@ "resolved": "../../../deps/phoenix_html", "link": true }, + "node_modules/photoswipe": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.3.tgz", + "integrity": "sha512-BUuulwZwkYFKADSe5xf0dd+wf6dws34ZvqP8R3oYHepRauOXoQHvw600sw1HlWd8K0S3LRCS4jxyR5fTuI383Q==", + "engines": { + "node": ">= 0.12.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -27464,13 +27463,8 @@ "jquery": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" - }, - "jquery-viewer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jquery-viewer/-/jquery-viewer-1.0.1.tgz", - "integrity": "sha512-d7qd/9zKCcsxgKDDt9nC2Jdbr2SdXcJkQVzQDxj/H7ZkXzS+scxt2KxGWQlsBthiRmvv9aCPt7kPnGsFA2ds/Q==", - "requires": {} + "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==", + "peer": true }, "js-base64": { "version": "2.6.4", @@ -29198,6 +29192,11 @@ "phoenix_html": { "version": "file:../../../deps/phoenix_html" }, + "photoswipe": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.3.tgz", + "integrity": "sha512-BUuulwZwkYFKADSe5xf0dd+wf6dws34ZvqP8R3oYHepRauOXoQHvw600sw1HlWd8K0S3LRCS4jxyR5fTuI383Q==" + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index eb004a2a9020..7e04b2dea29a 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -35,8 +35,6 @@ "highlight.js": "^11.7.0", "https-browserify": "^1.0.0", "humps": "^2.0.1", - "jquery": "^3.6.1", - "jquery-viewer": "^1.0.1", "js-cookie": "^3.0.1", "lodash.debounce": "^4.0.8", "lodash.differenceby": "^4.8.0", @@ -64,6 +62,7 @@ "path-parser": "^6.1.0", "phoenix": "file:../../../deps/phoenix", "phoenix_html": "file:../../../deps/phoenix_html", + "photoswipe": "^5.3.3", "pikaday": "^1.8.2", "popper.js": "^1.14.7", "reduce-reducers": "^1.0.4", diff --git a/apps/block_scout_web/assets/webpack.config.js b/apps/block_scout_web/assets/webpack.config.js index 29bce00a6aaf..caf148c7a005 100644 --- a/apps/block_scout_web/assets/webpack.config.js +++ b/apps/block_scout_web/assets/webpack.config.js @@ -85,6 +85,10 @@ const appJs = }, module: { rules: [ + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + }, { test: /\.js$/, exclude: /node_modules/, diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex index e60c6f216fb3..938b1607544f 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex @@ -10,7 +10,9 @@
<%= if is_nil(@error) do %>
- +
<% else %> <%= gettext("Cannot visualize contract")%>: <%= @error %> From 6b01b2c44f2c3598764cd0ee429f4df2c55952ba Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 8 Nov 2022 12:50:06 +0300 Subject: [PATCH 36/66] Add tooltip for image viewer --- .../templates/visualize_sol2uml/index.html.eex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex index 938b1607544f..d0615e41a8db 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex @@ -10,9 +10,11 @@
<%= if is_nil(@error) do %>
- + + +
<% else %> <%= gettext("Cannot visualize contract")%>: <%= @error %> From 5cddfa847ba6e59e08c4e25c4810ca8d5eb4d540 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 8 Nov 2022 17:18:15 +0300 Subject: [PATCH 37/66] Add visualizer to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b64bb1add79e..e3bbcfbbdbc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- [#6401](https://github.com/blockscout/blockscout/pull/6401) - Add Sol2Uml contract visualization - [#6444](https://github.com/blockscout/blockscout/pull/6444) - Add support for yul verification via rust microservice - [#6440](https://github.com/blockscout/blockscout/pull/6440) - Add support for base64 encoded NFT metadata - [#6407](https://github.com/blockscout/blockscout/pull/6407) - Indexed ratio for int txs fetching stage From a5e7d1dd837eb6f37d3965382ef71284c63c00cf Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Fri, 11 Nov 2022 12:04:54 +0300 Subject: [PATCH 38/66] Fix nil filename bug --- .../controllers/visualize_sol2uml_controller.ex | 6 +++++- apps/explorer/lib/explorer/visualize/sol2uml.ex | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex index d56cd89acdb1..92d9784fb2ba 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex @@ -23,7 +23,7 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do |> Enum.map(fn additional_source -> {additional_source.file_name, additional_source.contract_source_code} end) |> Enum.into(%{}) |> Map.merge(%{ - address.smart_contract.file_path => address.smart_contract.contract_source_code + get_contract_filename(address.smart_contract.file_path) => address.smart_contract.contract_source_code }) params = %{ @@ -39,6 +39,10 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do end end + def get_contract_filename(nil), do: "main.sol" + def get_contract_filename(filename), do: filename + + def index(conn, params) do not_found(conn) end diff --git a/apps/explorer/lib/explorer/visualize/sol2uml.ex b/apps/explorer/lib/explorer/visualize/sol2uml.ex index 879bf9ec54f4..cd7615cbcf3a 100644 --- a/apps/explorer/lib/explorer/visualize/sol2uml.ex +++ b/apps/explorer/lib/explorer/visualize/sol2uml.ex @@ -54,7 +54,7 @@ defmodule Explorer.Visualize.Sol2uml do def proccess_visualizer_response(other), do: {:error, other} - def visualize_contracts_url, do: "#{base_api_url()}" <> "/solidity:visualizeContracts" + def visualize_contracts_url, do: "#{base_api_url()}" <> "/solidity:visualize-contracts" def base_api_url, do: "#{base_url()}" <> "/api/v1" From 078ee26b7caa395ff79bd11d7f5d1e399df276dd Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Fri, 11 Nov 2022 12:09:46 +0300 Subject: [PATCH 39/66] Move new badge for sol2uml button --- .../templates/address_contract/index.html.eex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index a40d43ea276b..5904601a2bd3 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -103,9 +103,11 @@ <%= if visualize_sol2uml_enabled && !target_contract.is_vyper_contract do %> -
new
- - Sol2uml +
+ + Sol2uml +
new
+
<% end %> From f518a24a2b7f073fd9a356e43ad7cdd27d7bb06d Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Tue, 15 Nov 2022 21:55:40 +0300 Subject: [PATCH 40/66] Fix pr issues for sol2uml --- apps/block_scout_web/assets/webpack.config.js | 2 +- .../visualize_sol2uml_controller.ex | 20 ++++++++----------- .../visualize_sol2uml/index.html.eex | 4 ++-- .../lib/block_scout_web/web_router.ex | 2 +- .../lib/explorer/visualize/sol2uml.ex | 5 +++-- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/block_scout_web/assets/webpack.config.js b/apps/block_scout_web/assets/webpack.config.js index caf148c7a005..321a7f8947ea 100644 --- a/apps/block_scout_web/assets/webpack.config.js +++ b/apps/block_scout_web/assets/webpack.config.js @@ -57,7 +57,7 @@ const appJs = 'admin-tasks': './js/pages/admin/tasks.js', 'token-contract': './js/pages/token_contract.js', 'smart-contract-helpers': './js/lib/smart_contract/index.js', - 'img_viewer': './js/pages/img_viewer.js', + 'img-viewer': './js/pages/img_viewer.js', 'token-transfers-toggle': './js/lib/token_transfers_toggle.js', 'try-api': './js/lib/try_api.js', 'try-eth-api': './js/lib/try_eth_api.js', diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex index 92d9784fb2ba..b40011760e7c 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex @@ -6,18 +6,15 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do def index(conn, %{"address" => address_hash_string}) do address_options = [ necessity_by_association: %{ - :contracts_creation_internal_transaction => :optional, - :names => :optional, - :smart_contract => :optional, - :token => :optional, - :contracts_creation_transaction => :optional + :smart_contract => :optional } ] with true <- Sol2uml.enabled?(), - true <- Chain.smart_contract_fully_verified?(address_hash_string), {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do + {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true), + # check that contract is verified. partial and twin verification is ok for this case + false <- is_nil(address.smart_contract) do sources = address.smart_contract_additional_sources |> Enum.map(fn additional_source -> {additional_source.file_name, additional_source.contract_source_code} end) @@ -39,11 +36,10 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do end end - def get_contract_filename(nil), do: "main.sol" - def get_contract_filename(filename), do: filename - - - def index(conn, params) do + def index(conn, _) do not_found(conn) end + + def get_contract_filename(nil), do: "main.sol" + def get_contract_filename(filename), do: filename end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex index d0615e41a8db..79a9d20af18d 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex @@ -12,7 +12,7 @@
@@ -21,5 +21,5 @@ <% end %>
- + diff --git a/apps/block_scout_web/lib/block_scout_web/web_router.ex b/apps/block_scout_web/lib/block_scout_web/web_router.ex index c356489ff189..d039ae9b1236 100644 --- a/apps/block_scout_web/lib/block_scout_web/web_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/web_router.ex @@ -494,7 +494,7 @@ defmodule BlockScoutWeb.WebRouter do get("/token-counters", Tokens.TokenController, :token_counters) - get("/vis/sol2uml", VisualizeSol2umlController, :index) + get("/visualize/sol2uml", VisualizeSol2umlController, :index) get("/*path", PageNotFoundController, :index) end diff --git a/apps/explorer/lib/explorer/visualize/sol2uml.ex b/apps/explorer/lib/explorer/visualize/sol2uml.ex index cd7615cbcf3a..e9281b3ca153 100644 --- a/apps/explorer/lib/explorer/visualize/sol2uml.ex +++ b/apps/explorer/lib/explorer/visualize/sol2uml.ex @@ -19,8 +19,9 @@ defmodule Explorer.Visualize.Sol2uml do {:ok, %Response{body: body, status_code: 200}} -> proccess_visualizer_response(body) - {:ok, %Response{body: body, status_code: _}} -> - proccess_visualizer_response(body) + {:ok, %Response{body: body, status_code: status_code}} -> + Logger.error(fn -> ["Invalid status code from visualizer: #{status_code}. body: ", inspect(body)] end) + {:error, "failed to visualize contract"} {:error, error} -> old_truncate = Application.get_env(:logger, :truncate) From a9b6eca3b5fa44934f785ff99b698d8f07993a6d Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Wed, 16 Nov 2022 17:57:06 +0300 Subject: [PATCH 41/66] Add async loading of contract visualization --- .../assets/js/pages/img_viewer.js | 20 ----- .../assets/js/pages/sol2uml.js | 85 +++++++++++++++++++ apps/block_scout_web/assets/webpack.config.js | 2 +- .../visualize_sol2uml_controller.ex | 53 +++++++----- .../visualize_sol2uml/index.html.eex | 25 +++--- 5 files changed, 134 insertions(+), 51 deletions(-) delete mode 100644 apps/block_scout_web/assets/js/pages/img_viewer.js create mode 100644 apps/block_scout_web/assets/js/pages/sol2uml.js diff --git a/apps/block_scout_web/assets/js/pages/img_viewer.js b/apps/block_scout_web/assets/js/pages/img_viewer.js deleted file mode 100644 index 9b9e26749d47..000000000000 --- a/apps/block_scout_web/assets/js/pages/img_viewer.js +++ /dev/null @@ -1,20 +0,0 @@ -import 'viewerjs/dist/viewer.min.css'; -import Viewer from 'viewerjs'; -const gallery = document.getElementById('gallery'); -const viewer = new Viewer(gallery, { - inline: false, - toolbar: { - zoomIn: 2, - zoomOut: 4, - oneToOne: 4, - reset: 4, - play: { - show: 4, - size: 'large', - }, - rotateLeft: 4, - rotateRight: 4, - flipHorizontal: 4, - flipVertical: 4, - } -}); diff --git a/apps/block_scout_web/assets/js/pages/sol2uml.js b/apps/block_scout_web/assets/js/pages/sol2uml.js new file mode 100644 index 000000000000..4d24361b5f81 --- /dev/null +++ b/apps/block_scout_web/assets/js/pages/sol2uml.js @@ -0,0 +1,85 @@ +import 'viewerjs/dist/viewer.min.css' +import Viewer from 'viewerjs' +import $ from 'jquery' +import { createStore, connectElements } from '../lib/redux_helpers.js' + +export const initialState = { + contract_svg: null, + visualize_error: null +} + +export function reducer (state = initialState, action) { + switch (action.type) { + case 'SVG_FETCHED': { + return Object.assign({}, state, { + contract_svg: action.contract_svg, + visualize_error: action.error + }) + } + default: + return state + } +} + +const elements = { + '[data-selector="contract-image"]': { + render ($el, state, oldState) { + if (state.contract_svg) { + console.log('Got svg from server') + $('#spinner').hide() + $('#gallery img').attr('src', 'data:image/svg+xml;base64,' + state.contract_svg) + const gallery = document.getElementById('gallery') + const viewer = new Viewer(gallery, { + inline: false, + toolbar: { + zoomIn: 2, + zoomOut: 4, + oneToOne: 4, + reset: 4, + play: { + show: 4, + size: 'large' + }, + rotateLeft: 4, + rotateRight: 4, + flipHorizontal: 4, + flipVertical: 4 + } + }) + viewer.update() + $el.show() + } else if (state.visualize_error) { + console.log('Got error from server') + + $('#spinner').hide() + $el.empty().text('Cannot visalize contract: ' + state.visualize_error) + $el.show() + } else { + $('#spinner').show() + $el.hide() + } + } + } +} + +function loadSvg (store) { + const $element = $('[data-async-contract-svg]') + const path = $element.data().asyncContractSvg + + function fetchSvg () { + $.getJSON(path) + .done((response) => { + store.dispatch(Object.assign({ type: 'SVG_FETCHED' }, response)) + }) + } + + fetchSvg() +} + +function main () { + const store = createStore(reducer) + connectElements({ store, elements }) + loadSvg(store) +} + +main() diff --git a/apps/block_scout_web/assets/webpack.config.js b/apps/block_scout_web/assets/webpack.config.js index 321a7f8947ea..d4f59631be08 100644 --- a/apps/block_scout_web/assets/webpack.config.js +++ b/apps/block_scout_web/assets/webpack.config.js @@ -57,7 +57,7 @@ const appJs = 'admin-tasks': './js/pages/admin/tasks.js', 'token-contract': './js/pages/token_contract.js', 'smart-contract-helpers': './js/lib/smart_contract/index.js', - 'img-viewer': './js/pages/img_viewer.js', + 'sol2uml': './js/pages/sol2uml.js', 'token-transfers-toggle': './js/lib/token_transfers_toggle.js', 'try-api': './js/lib/try_api.js', 'try-eth-api': './js/lib/try_eth_api.js', diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex index b40011760e7c..b3955c109086 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex @@ -3,34 +3,49 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do alias Explorer.Chain alias Explorer.Visualize.Sol2uml - def index(conn, %{"address" => address_hash_string}) do + def index(conn, %{"type" => "JSON", "address" => address_hash_string}) do address_options = [ necessity_by_association: %{ :smart_contract => :optional } ] - with true <- Sol2uml.enabled?(), - {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), - {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true), - # check that contract is verified. partial and twin verification is ok for this case - false <- is_nil(address.smart_contract) do - sources = - address.smart_contract_additional_sources - |> Enum.map(fn additional_source -> {additional_source.file_name, additional_source.contract_source_code} end) - |> Enum.into(%{}) - |> Map.merge(%{ - get_contract_filename(address.smart_contract.file_path) => address.smart_contract.contract_source_code - }) + if Sol2uml.enabled?() do + with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), + {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true), + # check that contract is verified. partial and twin verification is ok for this case + false <- is_nil(address.smart_contract) do + sources = + address.smart_contract_additional_sources + |> Enum.map(fn additional_source -> {additional_source.file_name, additional_source.contract_source_code} end) + |> Enum.into(%{}) + |> Map.merge(%{ + get_contract_filename(address.smart_contract.file_path) => address.smart_contract.contract_source_code + }) - params = %{ - sources: sources - } + params = %{ + sources: sources + } - case Sol2uml.visualize_contracts(params) do - {:ok, svg} -> render(conn, "index.html", address: address, svg: svg, error: nil) - {:error, error} -> render(conn, "index.html", address: address, svg: nil, error: error) + case Sol2uml.visualize_contracts(params) do + {:ok, svg} -> json(conn, %{"address" => address.hash, "contract_svg" => svg, "error" => nil}) + {:error, error} -> json(conn, %{"address" => address.hash, "contract_svg" => nil, "error" => error}) + end + else + _ -> json(conn, %{error: "contract not found or unverified"}) end + else + not_found(conn) + end + end + + def index(conn, %{"address" => address_hash_string}) do + with true <- Sol2uml.enabled?(), + {:ok, _} <- Chain.string_to_address_hash(address_hash_string) do + render(conn, "index.html", + address: address_hash_string, + get_svg_path: visualize_sol2uml_path(conn, :index, %{"type" => "JSON", "address" => address_hash_string}) + ) else _ -> not_found(conn) end diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex index 79a9d20af18d..46758d9a446a 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex @@ -1,25 +1,28 @@
-
+

<%= gettext("UML diagram") %>

<%= gettext("For contract") %> <%= link( - @address.hash, - to: address_contract_path(@conn, :index, @address.hash) + @address, + to: address_contract_path(@conn, :index, @address) ) %>
- <%= if is_nil(@error) do %>
- + + + + + +
+ - + +
- <% else %> - <%= gettext("Cannot visualize contract")%>: <%= @error %> - <% end %>
- +
From cce19f2bbe35f97e8f8171b319da24f5ec00bd9c Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Wed, 16 Nov 2022 20:49:20 +0300 Subject: [PATCH 42/66] Add translation keys --- apps/block_scout_web/priv/gettext/default.pot | 466 +++++++++--------- .../priv/gettext/en/LC_MESSAGES/default.po | 466 +++++++++--------- 2 files changed, 476 insertions(+), 456 deletions(-) diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index ace26ccbff2d..ae907d6d85ed 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -76,6 +76,11 @@ msgstr "" msgid "(query)" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#, elixir-autogen, elixir-format +msgid ") may be added for each contract. Click the Add Library button to add an additional one." +msgstr "" + #: lib/block_scout_web/templates/layout/app.html.eex:230 #, elixir-autogen, elixir-format msgid "- We're indexing this chain right now. Some of the counts may be inaccurate." @@ -92,6 +97,11 @@ msgstr "" msgid "A block producer who successfully included the block onto the blockchain." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#, elixir-autogen, elixir-format +msgid "A library name called in the .sol file. Multiple libraries (up to " +msgstr "" + #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:73 #, elixir-autogen, elixir-format msgid "A string with the name of the action to be invoked." @@ -256,6 +266,11 @@ msgstr "" msgid "Address of the token contract" msgstr "" +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:8 +#, elixir-autogen, elixir-format +msgid "Address used in token mintings and burnings." +msgstr "" + #: lib/block_scout_web/templates/account/public_tags_request/address_field.html.eex:2 #, elixir-autogen, elixir-format msgid "Address*" @@ -284,7 +299,7 @@ msgstr "" msgid "All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:27 +#: lib/block_scout_web/templates/address_contract/index.html.eex:28 #, elixir-autogen, elixir-format msgid "All metadata displayed below is from that contract. In order to verify current contract, click" msgstr "" @@ -363,6 +378,16 @@ msgstr "" msgid "Balance" msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:35 +#, elixir-autogen, elixir-format +msgid "Balance after" +msgstr "" + +#: lib/block_scout_web/templates/transaction_state/index.html.eex:32 +#, elixir-autogen, elixir-format +msgid "Balance before" +msgstr "" + #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:14 #, elixir-autogen, elixir-format msgid "Balances" @@ -448,6 +473,11 @@ msgstr "" msgid "BlockScout provides analytics data, API, and Smart Contract tools for the %{subnetwork}" msgstr "" +#: lib/block_scout_web/templates/layout/_topnav.html.eex:29 +#, elixir-autogen, elixir-format +msgid "Blockchain" +msgstr "" + #: lib/block_scout_web/templates/chain/show.html.eex:153 #: lib/block_scout_web/templates/layout/_topnav.html.eex:34 #: lib/block_scout_web/templates/layout/_topnav.html.eex:38 @@ -468,11 +498,21 @@ msgstr "" msgid "Blocks Validated" msgstr "" +#: lib/block_scout_web/templates/layout/app.html.eex:44 +#, elixir-autogen, elixir-format +msgid "Blocks With Internal Transactions Indexed" +msgstr "" + #: lib/block_scout_web/templates/layout/_footer.html.eex:22 #, elixir-autogen, elixir-format msgid "Blockscout is a tool for inspecting and analyzing EVM based blockchains. Blockchain explorer for Ethereum Networks." msgstr "" +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 +#, elixir-autogen, elixir-format +msgid "Burn address" +msgstr "" + #: lib/block_scout_web/templates/block/_tile.html.eex:64 #: lib/block_scout_web/templates/block/overview.html.eex:216 #, elixir-autogen, elixir-format @@ -513,6 +553,11 @@ msgstr "" msgid "Cancel" msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:38 +#, elixir-autogen, elixir-format +msgid "Change" +msgstr "" + #: lib/block_scout_web/templates/layout/_footer.html.eex:41 #, elixir-autogen, elixir-format msgid "Chat (#blockscout)" @@ -575,7 +620,7 @@ msgstr "" msgid "Compiler" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:65 +#: lib/block_scout_web/templates/address_contract/index.html.eex:66 #, elixir-autogen, elixir-format msgid "Compiler version" msgstr "" @@ -629,18 +674,23 @@ msgstr "" msgid "Connection Lost, click to load newer validations" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:90 +#: lib/block_scout_web/templates/address_contract/index.html.eex:91 #, elixir-autogen, elixir-format msgid "Constructor Arguments" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:72 +#, elixir-autogen, elixir-format +msgid "Constructor args" +msgstr "" + #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:52 #: lib/block_scout_web/templates/transaction/overview.html.eex:227 #, elixir-autogen, elixir-format msgid "Contract" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:123 +#: lib/block_scout_web/templates/address_contract/index.html.eex:137 #, elixir-autogen, elixir-format msgid "Contract ABI" msgstr "" @@ -670,8 +720,8 @@ msgstr "" msgid "Contract Creation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:140 -#: lib/block_scout_web/templates/address_contract/index.html.eex:155 +#: lib/block_scout_web/templates/address_contract/index.html.eex:154 +#: lib/block_scout_web/templates/address_contract/index.html.eex:169 #, elixir-autogen, elixir-format msgid "Contract Creation Code" msgstr "" @@ -688,23 +738,38 @@ msgstr "" msgid "Contract Name" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:25 +#: lib/block_scout_web/templates/address_contract/index.html.eex:26 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:11 #, elixir-autogen, elixir-format msgid "Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:57 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:41 +#, elixir-autogen, elixir-format +msgid "Contract name or address" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:58 #, elixir-autogen, elixir-format msgid "Contract name:" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:100 +#: lib/block_scout_web/templates/address_contract/index.html.eex:101 #, elixir-autogen, elixir-format msgid "Contract source code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:146 +#: lib/block_scout_web/templates/address/overview.html.eex:120 +#, elixir-autogen, elixir-format +msgid "Contract was precompiled and created at genesis or contract creation transaction is missing" +msgstr "" + +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:5 +#, elixir-autogen, elixir-format +msgid "Contracts" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:160 #, elixir-autogen, elixir-format msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -714,7 +779,7 @@ msgstr "" msgid "Contribute" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:125 +#: lib/block_scout_web/templates/address_contract/index.html.eex:139 #, elixir-autogen, elixir-format msgid "Copy ABI" msgstr "" @@ -746,8 +811,8 @@ msgstr "" msgid "Copy Contract Address" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:142 -#: lib/block_scout_web/templates/address_contract/index.html.eex:158 +#: lib/block_scout_web/templates/address_contract/index.html.eex:156 +#: lib/block_scout_web/templates/address_contract/index.html.eex:172 #, elixir-autogen, elixir-format msgid "Copy Contract Creation Code" msgstr "" @@ -757,8 +822,8 @@ msgstr "" msgid "Copy Decompiled Contract Code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:179 -#: lib/block_scout_web/templates/address_contract/index.html.eex:189 +#: lib/block_scout_web/templates/address_contract/index.html.eex:193 +#: lib/block_scout_web/templates/address_contract/index.html.eex:203 #, elixir-autogen, elixir-format msgid "Copy Deployed ByteCode" msgstr "" @@ -794,8 +859,8 @@ msgstr "" msgid "Copy Raw Trace" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:102 -#: lib/block_scout_web/templates/address_contract/index.html.eex:113 +#: lib/block_scout_web/templates/address_contract/index.html.eex:115 +#: lib/block_scout_web/templates/address_contract/index.html.eex:127 #, elixir-autogen, elixir-format msgid "Copy Source Code" msgstr "" @@ -966,8 +1031,8 @@ msgstr "" msgid "Delegate Call" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:177 -#: lib/block_scout_web/templates/address_contract/index.html.eex:185 +#: lib/block_scout_web/templates/address_contract/index.html.eex:191 +#: lib/block_scout_web/templates/address_contract/index.html.eex:199 #, elixir-autogen, elixir-format msgid "Deployed ByteCode" msgstr "" @@ -997,7 +1062,7 @@ msgstr "" msgid "Difficulty" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:147 +#: lib/block_scout_web/templates/address_contract/index.html.eex:161 #, elixir-autogen, elixir-format msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1012,6 +1077,11 @@ msgstr "" msgid "Drop all Solidity contract source files into the drop zone." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:72 +#, elixir-autogen, elixir-format +msgid "Drop all Solidity or Yul contract source files into the drop zone." +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:18 #, elixir-autogen, elixir-format msgid "Drop sources and metadata JSON file or click here" @@ -1072,7 +1142,7 @@ msgstr "" msgid "ETH RPC API Documentation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:76 +#: lib/block_scout_web/templates/address_contract/index.html.eex:77 #: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:22 #, elixir-autogen, elixir-format @@ -1190,7 +1260,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:214 +#: lib/block_scout_web/templates/address_contract/index.html.eex:228 #, elixir-autogen, elixir-format msgid "External libraries" msgstr "" @@ -1239,11 +1309,21 @@ msgstr "" msgid "Fetching transfers..." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:15 +#, elixir-autogen, elixir-format +msgid "Filter by compiler:" +msgstr "" + #: lib/block_scout_web/templates/admin/dashboard/index.html.eex:16 #, elixir-autogen, elixir-format msgid "For any existing contracts in the database, insert all ABI entries into the contract_methods table. Use this in case you have verified smart contracts before early March 2019 and you want other contracts with the same functions to show those ABI's as candidate matches." msgstr "" +#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:6 +#, elixir-autogen, elixir-format +msgid "For contract" +msgstr "" + #: lib/block_scout_web/templates/layout/_topnav.html.eex:44 #, elixir-autogen, elixir-format msgid "Forked Blocks (Reorgs)" @@ -1453,11 +1533,22 @@ msgstr "" msgid "Inventory" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Is Yul contract" +msgstr "" + #: lib/block_scout_web/templates/transaction/not_found.html.eex:16 #, elixir-autogen, elixir-format msgid "It could still be in the TX Pool of a different node, waiting to be broadcasted." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:13 +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:26 +#, elixir-autogen, elixir-format +msgid "Last 24h" +msgstr "" + #: lib/block_scout_web/templates/address/overview.html.eex:259 #, elixir-autogen, elixir-format msgid "Last Balance Update" @@ -1474,6 +1565,12 @@ msgstr "" msgid "Less than" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex:4 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex:4 +#, elixir-autogen, elixir-format +msgid "Library" +msgstr "" + #: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:24 #, elixir-autogen, elixir-format msgid "License Expires" @@ -1559,6 +1656,11 @@ msgstr "" msgid "Market Cap" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:78 +#, elixir-autogen, elixir-format +msgid "Market cap" +msgstr "" + #: lib/block_scout_web/templates/transaction/overview.html.eex:382 #, elixir-autogen, elixir-format msgid "Max Fee per Gas" @@ -1654,6 +1756,12 @@ msgstr "" msgid "Must match the name specified in the code. For example, in contract MyContract {..} MyContract is the contract name." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:21 +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:58 +#, elixir-autogen, elixir-format +msgid "N/A" +msgstr "" + #: lib/block_scout_web/templates/block/overview.html.eex:116 #, elixir-autogen, elixir-format msgid "N/A bytes" @@ -1717,6 +1825,11 @@ msgstr "" msgid "New Solidity Smart Contract Verification" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:7 +#, elixir-autogen, elixir-format +msgid "New Solidity/Yul Smart Contract Verification" +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_vyper/new.html.eex:7 #, elixir-autogen, elixir-format msgid "New Vyper Smart Contract Verification" @@ -1797,12 +1910,17 @@ msgstr "" msgid "Only the first" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:61 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:69 +#, elixir-autogen, elixir-format +msgid "Optimization" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:62 #, elixir-autogen, elixir-format msgid "Optimization enabled" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:70 +#: lib/block_scout_web/templates/address_contract/index.html.eex:71 #: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:62 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:54 #, elixir-autogen, elixir-format @@ -2115,6 +2233,11 @@ msgstr "" msgid "Search tokens" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select Yes if you want to vefify Yul contract." +msgstr "" + #: lib/block_scout_web/views/internal_transaction_view.ex:27 #, elixir-autogen, elixir-format msgid "Self-Destruct" @@ -2192,6 +2315,13 @@ msgstr "" msgid "Smart contract / Address (0x...)" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:26 +#: lib/block_scout_web/views/verified_contracts_view.ex:9 +#, elixir-autogen, elixir-format +msgid "Solidity" +msgstr "" + #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:30 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:50 #: lib/block_scout_web/templates/address_logs/index.html.eex:23 @@ -2232,6 +2362,11 @@ msgstr "" msgid "Sources *.sol files" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63 +#, elixir-autogen, elixir-format +msgid "Sources *.sol or *.yul files" +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:14 #, elixir-autogen, elixir-format msgid "Sources and Metadata JSON" @@ -2247,6 +2382,13 @@ msgstr "" msgid "Standard Input JSON" msgstr "" +#: lib/block_scout_web/templates/transaction/_tabs.html.eex:29 +#: lib/block_scout_web/templates/transaction_state/index.html.eex:6 +#: lib/block_scout_web/views/transaction_view.ex:513 +#, elixir-autogen, elixir-format +msgid "State changes" +msgstr "" + #: lib/block_scout_web/views/internal_transaction_view.ex:24 #, elixir-autogen, elixir-format msgid "Static Call" @@ -2310,6 +2452,11 @@ msgstr "" msgid "The block height of a particular block is defined as the number of blocks preceding it in the blockchain." msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:13 +#, elixir-autogen, elixir-format +msgid "The changes from this transaction have not yet happened since the transaction is still pending." +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:26 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:18 #, elixir-autogen, elixir-format @@ -2453,6 +2600,11 @@ msgstr "" msgid "There are no transfers for this Token." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:93 +#, elixir-autogen, elixir-format +msgid "There are no verified contracts." +msgstr "" + #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:35 #, elixir-autogen, elixir-format msgid "There is no coin history for this address." @@ -2484,12 +2636,12 @@ msgstr "" msgid "This block has not been processed yet." msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:41 +#: lib/block_scout_web/templates/address_contract/index.html.eex:42 #, elixir-autogen, elixir-format msgid "This contract has been partially verified via Sourcify." msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:45 +#: lib/block_scout_web/templates/address_contract/index.html.eex:46 #, elixir-autogen, elixir-format msgid "This contract has been verified via Sourcify." msgstr "" @@ -2499,6 +2651,11 @@ msgstr "" msgid "This is useful to allow sending requests to blockscout without having to change anything about the request." msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:17 +#, elixir-autogen, elixir-format +msgid "This transaction hasn't changed state." +msgstr "" + #: lib/block_scout_web/templates/transaction/overview.html.eex:64 #, elixir-autogen, elixir-format msgid "This transaction is pending confirmation." @@ -2663,6 +2820,12 @@ msgstr "" msgid "Topics" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:9 +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:22 +#, elixir-autogen, elixir-format +msgid "Total" +msgstr "" + #: lib/block_scout_web/templates/block/overview.html.eex:169 #, elixir-autogen, elixir-format msgid "Total Difficulty" @@ -2818,6 +2981,11 @@ msgstr "" msgid "Tx/day" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:60 +#, elixir-autogen, elixir-format +msgid "Txns" +msgstr "" + #: lib/block_scout_web/templates/log/_data_decoded_view.html.eex:5 #: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:22 #, elixir-autogen, elixir-format @@ -2829,6 +2997,11 @@ msgstr "" msgid "Type of the token standard" msgstr "" +#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:5 +#, elixir-autogen, elixir-format +msgid "UML diagram" +msgstr "" + #: lib/block_scout_web/templates/transaction/overview.html.eex:461 #, elixir-autogen, elixir-format msgid "UTF-8" @@ -2916,6 +3089,11 @@ msgstr "" msgid "Value sent in the native token (and USD) if applicable." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7 +#, elixir-autogen, elixir-format +msgid "Verifed contracts, %{subnetwork}, %{coin}" +msgstr "" + #: lib/block_scout_web/templates/address_read_contract/index.html.eex:17 #: lib/block_scout_web/templates/address_write_contract/index.html.eex:15 #: lib/block_scout_web/templates/verified_contracts/index.html.eex:75 @@ -2923,15 +3101,31 @@ msgstr "" msgid "Verified" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:82 +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:18 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:6 +#, elixir-autogen, elixir-format +msgid "Verified Contracts" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:83 #, elixir-autogen, elixir-format msgid "Verified at" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:27 -#: lib/block_scout_web/templates/address_contract/index.html.eex:29 -#: lib/block_scout_web/templates/address_contract/index.html.eex:163 -#: lib/block_scout_web/templates/address_contract/index.html.eex:194 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:68 +#, elixir-autogen, elixir-format +msgid "Verified contracts" +msgstr "" + +#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:2 +#, elixir-autogen, elixir-format +msgid "Verified contracts - %{subnetwork} Explorer" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:28 +#: lib/block_scout_web/templates/address_contract/index.html.eex:30 +#: lib/block_scout_web/templates/address_contract/index.html.eex:177 +#: lib/block_scout_web/templates/address_contract/index.html.eex:208 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 #, elixir-autogen, elixir-format msgid "Verify & Publish" @@ -3025,11 +3219,23 @@ msgstr "" msgid "View the transactions, token transfers, and uncles for block number %{block_number}" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:8 +#, elixir-autogen, elixir-format +msgid "View the verified contracts on %{subnetwork}" +msgstr "" + #: lib/block_scout_web/templates/transaction/_metatags.html.eex:10 #, elixir-autogen, elixir-format msgid "View transaction %{transaction} on %{subnetwork}" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:32 +#: lib/block_scout_web/views/verified_contracts_view.ex:10 +#, elixir-autogen, elixir-format +msgid "Vyper" +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:46 #, elixir-autogen, elixir-format msgid "Vyper contract" @@ -3160,7 +3366,7 @@ msgstr "" msgid "burned from transactions included in the block (Base fee (per unit of gas) * Gas Used)." msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:27 +#: lib/block_scout_web/templates/address_contract/index.html.eex:28 #, elixir-autogen, elixir-format msgid "button" msgstr "" @@ -3255,199 +3461,3 @@ msgstr "" #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 -#, elixir-autogen, elixir-format -msgid ") may be added for each contract. Click the Add Library button to add an additional one." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 -#, elixir-autogen, elixir-format -msgid "A library name called in the .sol file. Multiple libraries (up to " -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex:4 -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex:4 -#, elixir-autogen, elixir-format -msgid "Library" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:8 -#, elixir-autogen, elixir-format -msgid "Address used in token mintings and burnings." -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:35 -#, elixir-autogen, elixir-format -msgid "Balance after" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:32 -#, elixir-autogen, elixir-format -msgid "Balance before" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 -#, elixir-autogen, elixir-format -msgid "Burn address" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:38 -#, elixir-autogen, elixir-format -msgid "Change" -msgstr "" - -#: lib/block_scout_web/templates/transaction/_tabs.html.eex:29 -#: lib/block_scout_web/templates/transaction_state/index.html.eex:6 -#: lib/block_scout_web/views/transaction_view.ex:513 -#, elixir-autogen, elixir-format -msgid "State changes" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:13 -#, elixir-autogen, elixir-format -msgid "The changes from this transaction have not yet happened since the transaction is still pending." -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:17 -#, elixir-autogen, elixir-format -msgid "This transaction hasn't changed state." -msgstr "" - -#: lib/block_scout_web/templates/address/overview.html.eex:120 -#, elixir-autogen, elixir-format -msgid "Contract was precompiled and created at genesis or contract creation transaction is missing" -msgstr "" - -#: lib/block_scout_web/templates/layout/_topnav.html.eex:29 -#, elixir-autogen, elixir-format -msgid "Blockchain" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:72 -#, elixir-autogen, elixir-format -msgid "Constructor args" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:41 -#, elixir-autogen, elixir-format -msgid "Contract name or address" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:5 -#, elixir-autogen, elixir-format -msgid "Contracts" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:15 -#, elixir-autogen, elixir-format -msgid "Filter by compiler:" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:13 -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:26 -#, elixir-autogen, elixir-format -msgid "Last 24h" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:78 -#, elixir-autogen, elixir-format -msgid "Market cap" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:21 -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:58 -#, elixir-autogen, elixir-format -msgid "N/A" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:69 -#, elixir-autogen, elixir-format -msgid "Optimization" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:26 -#: lib/block_scout_web/views/verified_contracts_view.ex:9 -#, elixir-autogen, elixir-format -msgid "Solidity" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:93 -#, elixir-autogen, elixir-format -msgid "There are no verified contracts." -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:9 -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:22 -#, elixir-autogen, elixir-format -msgid "Total" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:60 -#, elixir-autogen, elixir-format -msgid "Txns" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:18 -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:6 -#, elixir-autogen, elixir-format -msgid "Verified Contracts" -msgstr "" - -#: lib/block_scout_web/templates/layout/_topnav.html.eex:68 -#, elixir-autogen, elixir-format -msgid "Verified contracts" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:2 -#, elixir-autogen, elixir-format -msgid "Verified contracts - %{subnetwork} Explorer" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:8 -#, elixir-autogen, elixir-format -msgid "View the verified contracts on %{subnetwork}" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:32 -#: lib/block_scout_web/views/verified_contracts_view.ex:10 -#, elixir-autogen, elixir-format -msgid "Vyper" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7 -#, elixir-autogen, elixir-format -msgid "Verifed contracts, %{subnetwork}, %{coin}" -msgstr "" - -#: lib/block_scout_web/templates/layout/app.html.eex:44 -#, elixir-autogen, elixir-format -msgid "Blocks With Internal Transactions Indexed" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:72 -#, elixir-autogen, elixir-format -msgid "Drop all Solidity or Yul contract source files into the drop zone." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:7 -#, elixir-autogen, elixir-format -msgid "New Solidity/Yul Smart Contract Verification" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19 -#, elixir-autogen, elixir-format -msgid "Select Yes if you want to vefify Yul contract." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63 -#, elixir-autogen, elixir-format -msgid "Sources *.sol or *.yul files" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:3 -#, elixir-autogen, elixir-format -msgid "Is Yul contract" -msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 3a9c3f463765..ae907d6d85ed 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -76,6 +76,11 @@ msgstr "" msgid "(query)" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#, elixir-autogen, elixir-format +msgid ") may be added for each contract. Click the Add Library button to add an additional one." +msgstr "" + #: lib/block_scout_web/templates/layout/app.html.eex:230 #, elixir-autogen, elixir-format msgid "- We're indexing this chain right now. Some of the counts may be inaccurate." @@ -92,6 +97,11 @@ msgstr "" msgid "A block producer who successfully included the block onto the blockchain." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#, elixir-autogen, elixir-format +msgid "A library name called in the .sol file. Multiple libraries (up to " +msgstr "" + #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:73 #, elixir-autogen, elixir-format msgid "A string with the name of the action to be invoked." @@ -256,6 +266,11 @@ msgstr "" msgid "Address of the token contract" msgstr "" +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:8 +#, elixir-autogen, elixir-format +msgid "Address used in token mintings and burnings." +msgstr "" + #: lib/block_scout_web/templates/account/public_tags_request/address_field.html.eex:2 #, elixir-autogen, elixir-format msgid "Address*" @@ -284,7 +299,7 @@ msgstr "" msgid "All functions displayed below are from ABI of that contract. In order to verify current contract, proceed with" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:27 +#: lib/block_scout_web/templates/address_contract/index.html.eex:28 #, elixir-autogen, elixir-format msgid "All metadata displayed below is from that contract. In order to verify current contract, click" msgstr "" @@ -363,6 +378,16 @@ msgstr "" msgid "Balance" msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:35 +#, elixir-autogen, elixir-format +msgid "Balance after" +msgstr "" + +#: lib/block_scout_web/templates/transaction_state/index.html.eex:32 +#, elixir-autogen, elixir-format +msgid "Balance before" +msgstr "" + #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:14 #, elixir-autogen, elixir-format msgid "Balances" @@ -448,6 +473,11 @@ msgstr "" msgid "BlockScout provides analytics data, API, and Smart Contract tools for the %{subnetwork}" msgstr "" +#: lib/block_scout_web/templates/layout/_topnav.html.eex:29 +#, elixir-autogen, elixir-format +msgid "Blockchain" +msgstr "" + #: lib/block_scout_web/templates/chain/show.html.eex:153 #: lib/block_scout_web/templates/layout/_topnav.html.eex:34 #: lib/block_scout_web/templates/layout/_topnav.html.eex:38 @@ -468,11 +498,21 @@ msgstr "" msgid "Blocks Validated" msgstr "" +#: lib/block_scout_web/templates/layout/app.html.eex:44 +#, elixir-autogen, elixir-format +msgid "Blocks With Internal Transactions Indexed" +msgstr "" + #: lib/block_scout_web/templates/layout/_footer.html.eex:22 #, elixir-autogen, elixir-format msgid "Blockscout is a tool for inspecting and analyzing EVM based blockchains. Blockchain explorer for Ethereum Networks." msgstr "" +#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 +#, elixir-autogen, elixir-format +msgid "Burn address" +msgstr "" + #: lib/block_scout_web/templates/block/_tile.html.eex:64 #: lib/block_scout_web/templates/block/overview.html.eex:216 #, elixir-autogen, elixir-format @@ -513,6 +553,11 @@ msgstr "" msgid "Cancel" msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:38 +#, elixir-autogen, elixir-format +msgid "Change" +msgstr "" + #: lib/block_scout_web/templates/layout/_footer.html.eex:41 #, elixir-autogen, elixir-format msgid "Chat (#blockscout)" @@ -575,7 +620,7 @@ msgstr "" msgid "Compiler" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:65 +#: lib/block_scout_web/templates/address_contract/index.html.eex:66 #, elixir-autogen, elixir-format msgid "Compiler version" msgstr "" @@ -629,18 +674,23 @@ msgstr "" msgid "Connection Lost, click to load newer validations" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:90 +#: lib/block_scout_web/templates/address_contract/index.html.eex:91 #, elixir-autogen, elixir-format msgid "Constructor Arguments" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:72 +#, elixir-autogen, elixir-format +msgid "Constructor args" +msgstr "" + #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:52 #: lib/block_scout_web/templates/transaction/overview.html.eex:227 #, elixir-autogen, elixir-format msgid "Contract" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:123 +#: lib/block_scout_web/templates/address_contract/index.html.eex:137 #, elixir-autogen, elixir-format msgid "Contract ABI" msgstr "" @@ -670,8 +720,8 @@ msgstr "" msgid "Contract Creation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:140 -#: lib/block_scout_web/templates/address_contract/index.html.eex:155 +#: lib/block_scout_web/templates/address_contract/index.html.eex:154 +#: lib/block_scout_web/templates/address_contract/index.html.eex:169 #, elixir-autogen, elixir-format msgid "Contract Creation Code" msgstr "" @@ -688,23 +738,38 @@ msgstr "" msgid "Contract Name" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:25 +#: lib/block_scout_web/templates/address_contract/index.html.eex:26 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:11 #, elixir-autogen, elixir-format msgid "Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:57 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:41 +#, elixir-autogen, elixir-format +msgid "Contract name or address" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:58 #, elixir-autogen, elixir-format msgid "Contract name:" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:100 +#: lib/block_scout_web/templates/address_contract/index.html.eex:101 #, elixir-autogen, elixir-format msgid "Contract source code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:146 +#: lib/block_scout_web/templates/address/overview.html.eex:120 +#, elixir-autogen, elixir-format +msgid "Contract was precompiled and created at genesis or contract creation transaction is missing" +msgstr "" + +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:5 +#, elixir-autogen, elixir-format +msgid "Contracts" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:160 #, elixir-autogen, elixir-format msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -714,7 +779,7 @@ msgstr "" msgid "Contribute" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:125 +#: lib/block_scout_web/templates/address_contract/index.html.eex:139 #, elixir-autogen, elixir-format msgid "Copy ABI" msgstr "" @@ -746,8 +811,8 @@ msgstr "" msgid "Copy Contract Address" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:142 -#: lib/block_scout_web/templates/address_contract/index.html.eex:158 +#: lib/block_scout_web/templates/address_contract/index.html.eex:156 +#: lib/block_scout_web/templates/address_contract/index.html.eex:172 #, elixir-autogen, elixir-format msgid "Copy Contract Creation Code" msgstr "" @@ -757,8 +822,8 @@ msgstr "" msgid "Copy Decompiled Contract Code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:179 -#: lib/block_scout_web/templates/address_contract/index.html.eex:189 +#: lib/block_scout_web/templates/address_contract/index.html.eex:193 +#: lib/block_scout_web/templates/address_contract/index.html.eex:203 #, elixir-autogen, elixir-format msgid "Copy Deployed ByteCode" msgstr "" @@ -794,8 +859,8 @@ msgstr "" msgid "Copy Raw Trace" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:102 -#: lib/block_scout_web/templates/address_contract/index.html.eex:113 +#: lib/block_scout_web/templates/address_contract/index.html.eex:115 +#: lib/block_scout_web/templates/address_contract/index.html.eex:127 #, elixir-autogen, elixir-format msgid "Copy Source Code" msgstr "" @@ -966,8 +1031,8 @@ msgstr "" msgid "Delegate Call" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:177 -#: lib/block_scout_web/templates/address_contract/index.html.eex:185 +#: lib/block_scout_web/templates/address_contract/index.html.eex:191 +#: lib/block_scout_web/templates/address_contract/index.html.eex:199 #, elixir-autogen, elixir-format msgid "Deployed ByteCode" msgstr "" @@ -997,7 +1062,7 @@ msgstr "" msgid "Difficulty" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:147 +#: lib/block_scout_web/templates/address_contract/index.html.eex:161 #, elixir-autogen, elixir-format msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1012,6 +1077,11 @@ msgstr "" msgid "Drop all Solidity contract source files into the drop zone." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:72 +#, elixir-autogen, elixir-format +msgid "Drop all Solidity or Yul contract source files into the drop zone." +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:18 #, elixir-autogen, elixir-format msgid "Drop sources and metadata JSON file or click here" @@ -1072,7 +1142,7 @@ msgstr "" msgid "ETH RPC API Documentation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:76 +#: lib/block_scout_web/templates/address_contract/index.html.eex:77 #: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:30 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:22 #, elixir-autogen, elixir-format @@ -1190,7 +1260,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:214 +#: lib/block_scout_web/templates/address_contract/index.html.eex:228 #, elixir-autogen, elixir-format msgid "External libraries" msgstr "" @@ -1239,11 +1309,21 @@ msgstr "" msgid "Fetching transfers..." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:15 +#, elixir-autogen, elixir-format +msgid "Filter by compiler:" +msgstr "" + #: lib/block_scout_web/templates/admin/dashboard/index.html.eex:16 #, elixir-autogen, elixir-format msgid "For any existing contracts in the database, insert all ABI entries into the contract_methods table. Use this in case you have verified smart contracts before early March 2019 and you want other contracts with the same functions to show those ABI's as candidate matches." msgstr "" +#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:6 +#, elixir-autogen, elixir-format +msgid "For contract" +msgstr "" + #: lib/block_scout_web/templates/layout/_topnav.html.eex:44 #, elixir-autogen, elixir-format msgid "Forked Blocks (Reorgs)" @@ -1453,11 +1533,22 @@ msgstr "" msgid "Inventory" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Is Yul contract" +msgstr "" + #: lib/block_scout_web/templates/transaction/not_found.html.eex:16 #, elixir-autogen, elixir-format msgid "It could still be in the TX Pool of a different node, waiting to be broadcasted." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:13 +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:26 +#, elixir-autogen, elixir-format +msgid "Last 24h" +msgstr "" + #: lib/block_scout_web/templates/address/overview.html.eex:259 #, elixir-autogen, elixir-format msgid "Last Balance Update" @@ -1474,6 +1565,12 @@ msgstr "" msgid "Less than" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex:4 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex:4 +#, elixir-autogen, elixir-format +msgid "Library" +msgstr "" + #: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:24 #, elixir-autogen, elixir-format msgid "License Expires" @@ -1559,6 +1656,11 @@ msgstr "" msgid "Market Cap" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:78 +#, elixir-autogen, elixir-format +msgid "Market cap" +msgstr "" + #: lib/block_scout_web/templates/transaction/overview.html.eex:382 #, elixir-autogen, elixir-format msgid "Max Fee per Gas" @@ -1654,6 +1756,12 @@ msgstr "" msgid "Must match the name specified in the code. For example, in contract MyContract {..} MyContract is the contract name." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:21 +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:58 +#, elixir-autogen, elixir-format +msgid "N/A" +msgstr "" + #: lib/block_scout_web/templates/block/overview.html.eex:116 #, elixir-autogen, elixir-format msgid "N/A bytes" @@ -1717,6 +1825,11 @@ msgstr "" msgid "New Solidity Smart Contract Verification" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:7 +#, elixir-autogen, elixir-format +msgid "New Solidity/Yul Smart Contract Verification" +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_vyper/new.html.eex:7 #, elixir-autogen, elixir-format msgid "New Vyper Smart Contract Verification" @@ -1797,12 +1910,17 @@ msgstr "" msgid "Only the first" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:61 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:69 +#, elixir-autogen, elixir-format +msgid "Optimization" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:62 #, elixir-autogen, elixir-format msgid "Optimization enabled" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:70 +#: lib/block_scout_web/templates/address_contract/index.html.eex:71 #: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:62 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:54 #, elixir-autogen, elixir-format @@ -2115,6 +2233,11 @@ msgstr "" msgid "Search tokens" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select Yes if you want to vefify Yul contract." +msgstr "" + #: lib/block_scout_web/views/internal_transaction_view.ex:27 #, elixir-autogen, elixir-format msgid "Self-Destruct" @@ -2192,6 +2315,13 @@ msgstr "" msgid "Smart contract / Address (0x...)" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:26 +#: lib/block_scout_web/views/verified_contracts_view.ex:9 +#, elixir-autogen, elixir-format +msgid "Solidity" +msgstr "" + #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:30 #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:50 #: lib/block_scout_web/templates/address_logs/index.html.eex:23 @@ -2232,6 +2362,11 @@ msgstr "" msgid "Sources *.sol files" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63 +#, elixir-autogen, elixir-format +msgid "Sources *.sol or *.yul files" +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_via_json/new.html.eex:14 #, elixir-autogen, elixir-format msgid "Sources and Metadata JSON" @@ -2247,6 +2382,13 @@ msgstr "" msgid "Standard Input JSON" msgstr "" +#: lib/block_scout_web/templates/transaction/_tabs.html.eex:29 +#: lib/block_scout_web/templates/transaction_state/index.html.eex:6 +#: lib/block_scout_web/views/transaction_view.ex:513 +#, elixir-autogen, elixir-format +msgid "State changes" +msgstr "" + #: lib/block_scout_web/views/internal_transaction_view.ex:24 #, elixir-autogen, elixir-format msgid "Static Call" @@ -2310,6 +2452,11 @@ msgstr "" msgid "The block height of a particular block is defined as the number of blocks preceding it in the blockchain." msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:13 +#, elixir-autogen, elixir-format +msgid "The changes from this transaction have not yet happened since the transaction is still pending." +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:26 #: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:18 #, elixir-autogen, elixir-format @@ -2453,6 +2600,11 @@ msgstr "" msgid "There are no transfers for this Token." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:93 +#, elixir-autogen, elixir-format +msgid "There are no verified contracts." +msgstr "" + #: lib/block_scout_web/templates/address_coin_balance/index.html.eex:35 #, elixir-autogen, elixir-format msgid "There is no coin history for this address." @@ -2484,12 +2636,12 @@ msgstr "" msgid "This block has not been processed yet." msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:41 +#: lib/block_scout_web/templates/address_contract/index.html.eex:42 #, elixir-autogen, elixir-format msgid "This contract has been partially verified via Sourcify." msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:45 +#: lib/block_scout_web/templates/address_contract/index.html.eex:46 #, elixir-autogen, elixir-format msgid "This contract has been verified via Sourcify." msgstr "" @@ -2499,6 +2651,11 @@ msgstr "" msgid "This is useful to allow sending requests to blockscout without having to change anything about the request." msgstr "" +#: lib/block_scout_web/templates/transaction_state/index.html.eex:17 +#, elixir-autogen, elixir-format +msgid "This transaction hasn't changed state." +msgstr "" + #: lib/block_scout_web/templates/transaction/overview.html.eex:64 #, elixir-autogen, elixir-format msgid "This transaction is pending confirmation." @@ -2663,6 +2820,12 @@ msgstr "" msgid "Topics" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:9 +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:22 +#, elixir-autogen, elixir-format +msgid "Total" +msgstr "" + #: lib/block_scout_web/templates/block/overview.html.eex:169 #, elixir-autogen, elixir-format msgid "Total Difficulty" @@ -2818,6 +2981,11 @@ msgstr "" msgid "Tx/day" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:60 +#, elixir-autogen, elixir-format +msgid "Txns" +msgstr "" + #: lib/block_scout_web/templates/log/_data_decoded_view.html.eex:5 #: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:22 #, elixir-autogen, elixir-format @@ -2829,6 +2997,11 @@ msgstr "" msgid "Type of the token standard" msgstr "" +#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:5 +#, elixir-autogen, elixir-format +msgid "UML diagram" +msgstr "" + #: lib/block_scout_web/templates/transaction/overview.html.eex:461 #, elixir-autogen, elixir-format msgid "UTF-8" @@ -2916,6 +3089,11 @@ msgstr "" msgid "Value sent in the native token (and USD) if applicable." msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7 +#, elixir-autogen, elixir-format +msgid "Verifed contracts, %{subnetwork}, %{coin}" +msgstr "" + #: lib/block_scout_web/templates/address_read_contract/index.html.eex:17 #: lib/block_scout_web/templates/address_write_contract/index.html.eex:15 #: lib/block_scout_web/templates/verified_contracts/index.html.eex:75 @@ -2923,15 +3101,31 @@ msgstr "" msgid "Verified" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:82 +#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:18 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:6 +#, elixir-autogen, elixir-format +msgid "Verified Contracts" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:83 #, elixir-autogen, elixir-format msgid "Verified at" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:27 -#: lib/block_scout_web/templates/address_contract/index.html.eex:29 -#: lib/block_scout_web/templates/address_contract/index.html.eex:163 -#: lib/block_scout_web/templates/address_contract/index.html.eex:194 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:68 +#, elixir-autogen, elixir-format +msgid "Verified contracts" +msgstr "" + +#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:2 +#, elixir-autogen, elixir-format +msgid "Verified contracts - %{subnetwork} Explorer" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:28 +#: lib/block_scout_web/templates/address_contract/index.html.eex:30 +#: lib/block_scout_web/templates/address_contract/index.html.eex:177 +#: lib/block_scout_web/templates/address_contract/index.html.eex:208 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 #, elixir-autogen, elixir-format msgid "Verify & Publish" @@ -3025,11 +3219,23 @@ msgstr "" msgid "View the transactions, token transfers, and uncles for block number %{block_number}" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:8 +#, elixir-autogen, elixir-format +msgid "View the verified contracts on %{subnetwork}" +msgstr "" + #: lib/block_scout_web/templates/transaction/_metatags.html.eex:10 #, elixir-autogen, elixir-format msgid "View transaction %{transaction} on %{subnetwork}" msgstr "" +#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 +#: lib/block_scout_web/templates/verified_contracts/index.html.eex:32 +#: lib/block_scout_web/views/verified_contracts_view.ex:10 +#, elixir-autogen, elixir-format +msgid "Vyper" +msgstr "" + #: lib/block_scout_web/templates/address_contract_verification/new.html.eex:46 #, elixir-autogen, elixir-format msgid "Vyper contract" @@ -3160,7 +3366,7 @@ msgstr "" msgid "burned from transactions included in the block (Base fee (per unit of gas) * Gas Used)." msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:27 +#: lib/block_scout_web/templates/address_contract/index.html.eex:28 #, elixir-autogen, elixir-format msgid "button" msgstr "" @@ -3255,199 +3461,3 @@ msgstr "" #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 -#, elixir-autogen, elixir-format -msgid ") may be added for each contract. Click the Add Library button to add an additional one." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 -#, elixir-autogen, elixir-format, fuzzy -msgid "A library name called in the .sol file. Multiple libraries (up to " -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex:4 -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex:4 -#, elixir-autogen, elixir-format, fuzzy -msgid "Library" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:8 -#, elixir-autogen, elixir-format -msgid "Address used in token mintings and burnings." -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:35 -#, elixir-autogen, elixir-format, fuzzy -msgid "Balance after" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:32 -#, elixir-autogen, elixir-format, fuzzy -msgid "Balance before" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/_state_change.html.eex:9 -#, elixir-autogen, elixir-format -msgid "Burn address" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:38 -#, elixir-autogen, elixir-format -msgid "Change" -msgstr "" - -#: lib/block_scout_web/templates/transaction/_tabs.html.eex:29 -#: lib/block_scout_web/templates/transaction_state/index.html.eex:6 -#: lib/block_scout_web/views/transaction_view.ex:513 -#, elixir-autogen, elixir-format -msgid "State changes" -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:13 -#, elixir-autogen, elixir-format -msgid "The changes from this transaction have not yet happened since the transaction is still pending." -msgstr "" - -#: lib/block_scout_web/templates/transaction_state/index.html.eex:17 -#, elixir-autogen, elixir-format -msgid "This transaction hasn't changed state." -msgstr "" - -#: lib/block_scout_web/templates/address/overview.html.eex:120 -#, elixir-autogen, elixir-format -msgid "Contract was precompiled and created at genesis or contract creation transaction is missing" -msgstr "" - -#: lib/block_scout_web/templates/layout/_topnav.html.eex:29 -#, elixir-autogen, elixir-format, fuzzy -msgid "Blockchain" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:72 -#, elixir-autogen, elixir-format, fuzzy -msgid "Constructor args" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:41 -#, elixir-autogen, elixir-format, fuzzy -msgid "Contract name or address" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:5 -#, elixir-autogen, elixir-format, fuzzy -msgid "Contracts" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:15 -#, elixir-autogen, elixir-format -msgid "Filter by compiler:" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:13 -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:26 -#, elixir-autogen, elixir-format -msgid "Last 24h" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:78 -#, elixir-autogen, elixir-format, fuzzy -msgid "Market cap" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:21 -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:58 -#, elixir-autogen, elixir-format -msgid "N/A" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:69 -#, elixir-autogen, elixir-format, fuzzy -msgid "Optimization" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:26 -#: lib/block_scout_web/views/verified_contracts_view.ex:9 -#, elixir-autogen, elixir-format -msgid "Solidity" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:93 -#, elixir-autogen, elixir-format, fuzzy -msgid "There are no verified contracts." -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:9 -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:22 -#, elixir-autogen, elixir-format, fuzzy -msgid "Total" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:60 -#, elixir-autogen, elixir-format -msgid "Txns" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_stats.html.eex:18 -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:6 -#, elixir-autogen, elixir-format, fuzzy -msgid "Verified Contracts" -msgstr "" - -#: lib/block_scout_web/templates/layout/_topnav.html.eex:68 -#, elixir-autogen, elixir-format, fuzzy -msgid "Verified contracts" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:2 -#, elixir-autogen, elixir-format, fuzzy -msgid "Verified contracts - %{subnetwork} Explorer" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:8 -#, elixir-autogen, elixir-format -msgid "View the verified contracts on %{subnetwork}" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_contract.html.eex:28 -#: lib/block_scout_web/templates/verified_contracts/index.html.eex:32 -#: lib/block_scout_web/views/verified_contracts_view.ex:10 -#, elixir-autogen, elixir-format -msgid "Vyper" -msgstr "" - -#: lib/block_scout_web/templates/verified_contracts/_metatags.html.eex:7 -#, elixir-autogen, elixir-format, fuzzy -msgid "Verifed contracts, %{subnetwork}, %{coin}" -msgstr "" - -#: lib/block_scout_web/templates/layout/app.html.eex:44 -#, elixir-autogen, elixir-format, fuzzy -msgid "Blocks With Internal Transactions Indexed" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:72 -#, elixir-autogen, elixir-format, fuzzy -msgid "Drop all Solidity or Yul contract source files into the drop zone." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:7 -#, elixir-autogen, elixir-format, fuzzy -msgid "New Solidity/Yul Smart Contract Verification" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:19 -#, elixir-autogen, elixir-format -msgid "Select Yes if you want to vefify Yul contract." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:63 -#, elixir-autogen, elixir-format, fuzzy -msgid "Sources *.sol or *.yul files" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex:3 -#, elixir-autogen, elixir-format -msgid "Is Yul contract" -msgstr "" From 3e2e546ed72bbe299b9385ba622a84ab6c3d8a4b Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Wed, 23 Nov 2022 12:10:11 +0300 Subject: [PATCH 43/66] Fix sol2uml button layout --- .../templates/address_contract/index.html.eex | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index 5904601a2bd3..86e9f64cd6e2 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -99,21 +99,21 @@

<%= target_contract.file_path || gettext "Contract source code" %>

-
- <%= if visualize_sol2uml_enabled && !target_contract.is_vyper_contract do %> - - -
- - Sol2uml -
new
-
-
-
- <% end %> - +
+ <%= if visualize_sol2uml_enabled && !target_contract.is_vyper_contract && !is_nil(target_contract.abi) do %> + + +
+ + Sol2uml +
new
+
+
+
+ <% end %> +
><%= target_contract.contract_source_code %>

From 131d03b83226c751688706a46c5dde8e809878aa Mon Sep 17 00:00:00 2001
From: Lymarenko Lev 
Date: Thu, 24 Nov 2022 15:59:01 +0300
Subject: [PATCH 44/66] Fix pr issues

---
 .../block_scout_web/assets/js/pages/sol2uml.js |  5 +----
 apps/block_scout_web/assets/package-lock.json  |  7 +++----
 apps/block_scout_web/assets/package.json       |  1 +
 .../visualize_sol2uml_controller.ex            | 11 +++++++++--
 .../templates/visualize_sol2uml/index.html.eex | 18 +++++++++++++-----
 .../smart_contract/rust_verifier_interface.ex  |  9 +--------
 .../lib/explorer/utility/rust_service.ex       | 12 ++++++++++++
 .../explorer/lib/explorer/visualize/sol2uml.ex | 11 ++---------
 8 files changed, 42 insertions(+), 32 deletions(-)
 create mode 100644 apps/explorer/lib/explorer/utility/rust_service.ex

diff --git a/apps/block_scout_web/assets/js/pages/sol2uml.js b/apps/block_scout_web/assets/js/pages/sol2uml.js
index 4d24361b5f81..253f268a6bf8 100644
--- a/apps/block_scout_web/assets/js/pages/sol2uml.js
+++ b/apps/block_scout_web/assets/js/pages/sol2uml.js
@@ -25,7 +25,6 @@ const elements = {
   '[data-selector="contract-image"]': {
     render ($el, state, oldState) {
       if (state.contract_svg) {
-        console.log('Got svg from server')
         $('#spinner').hide()
         $('#gallery img').attr('src', 'data:image/svg+xml;base64,' + state.contract_svg)
         const gallery = document.getElementById('gallery')
@@ -49,10 +48,8 @@ const elements = {
         viewer.update()
         $el.show()
       } else if (state.visualize_error) {
-        console.log('Got error from server')
-
         $('#spinner').hide()
-        $el.empty().text('Cannot visalize contract: ' + state.visualize_error)
+        $el.empty().text('Cannot visualize contract: ' + state.visualize_error)
         $el.show()
       } else {
         $('#spinner').show()
diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json
index 24bc901f47ef..bd616a3a1d1b 100644
--- a/apps/block_scout_web/assets/package-lock.json
+++ b/apps/block_scout_web/assets/package-lock.json
@@ -23,6 +23,7 @@
         "highlight.js": "^11.7.0",
         "https-browserify": "^1.0.0",
         "humps": "^2.0.1",
+        "jquery": "^3.6.1",
         "js-cookie": "^3.0.1",
         "lodash.debounce": "^4.0.8",
         "lodash.differenceby": "^4.8.0",
@@ -11888,8 +11889,7 @@
     "node_modules/jquery": {
       "version": "3.6.1",
       "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
-      "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==",
-      "peer": true
+      "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw=="
     },
     "node_modules/js-base64": {
       "version": "2.6.4",
@@ -27463,8 +27463,7 @@
     "jquery": {
       "version": "3.6.1",
       "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
-      "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==",
-      "peer": true
+      "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw=="
     },
     "js-base64": {
       "version": "2.6.4",
diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json
index 7e04b2dea29a..b066d3788021 100644
--- a/apps/block_scout_web/assets/package.json
+++ b/apps/block_scout_web/assets/package.json
@@ -35,6 +35,7 @@
     "highlight.js": "^11.7.0",
     "https-browserify": "^1.0.0",
     "humps": "^2.0.1",
+    "jquery": "^3.6.1",
     "js-cookie": "^3.0.1",
     "lodash.debounce": "^4.0.8",
     "lodash.differenceby": "^4.8.0",
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex
index b3955c109086..3863fb31a8c6 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/visualize_sol2uml_controller.ex
@@ -40,10 +40,17 @@ defmodule BlockScoutWeb.VisualizeSol2umlController do
   end
 
   def index(conn, %{"address" => address_hash_string}) do
+    address_options = [
+      necessity_by_association: %{
+        :smart_contract => :optional
+      }
+    ]
+
     with true <- Sol2uml.enabled?(),
-         {:ok, _} <- Chain.string_to_address_hash(address_hash_string) do
+         {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
+         {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do
       render(conn, "index.html",
-        address: address_hash_string,
+        address: address,
         get_svg_path: visualize_sol2uml_path(conn, :index, %{"type" => "JSON", "address" => address_hash_string})
       )
     else
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex
index 46758d9a446a..b78d3ef514ec 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/visualize_sol2uml/index.html.eex
@@ -2,11 +2,19 @@
     
-

<%= gettext("UML diagram") %>

- <%= gettext("For contract") %> <%= link( - @address, - to: address_contract_path(@conn, :index, @address) - ) %> +
<%= gettext("UML diagram") %>
+

+ <%= gettext("For contract") %> + <%= link to: address_contract_path(@conn, :index, @address), "data-test": "address_hash_link" do %> + <%= render( + BlockScoutWeb.AddressView, + "_responsive_hash.html", + address: @address, + contract: true, + use_custom_tooltip: false + ) %> + <% end %> +

diff --git a/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex b/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex index e54fcddd7b62..8f3afb74c93b 100644 --- a/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex +++ b/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex @@ -137,14 +137,7 @@ defmodule Explorer.SmartContract.RustVerifierInterface do def base_api_url, do: "#{base_url()}" <> "/api/v1" def base_url do - url = Application.get_env(:explorer, __MODULE__)[:service_url] - - if String.ends_with?(url, "/") do - url - |> String.slice(0..(String.length(url) - 2)) - else - url - end + Explorer.Utility.RustService.base_url(__MODULE__) end def enabled?, do: Application.get_env(:explorer, __MODULE__)[:enabled] diff --git a/apps/explorer/lib/explorer/utility/rust_service.ex b/apps/explorer/lib/explorer/utility/rust_service.ex new file mode 100644 index 000000000000..97924a997567 --- /dev/null +++ b/apps/explorer/lib/explorer/utility/rust_service.ex @@ -0,0 +1,12 @@ +defmodule Explorer.Utility.RustService do + def base_url(module) do + url = Application.get_env(:explorer, module)[:service_url] + + if String.ends_with?(url, "/") do + url + |> String.slice(0..(String.length(url) - 2)) + else + url + end + end +end diff --git a/apps/explorer/lib/explorer/visualize/sol2uml.ex b/apps/explorer/lib/explorer/visualize/sol2uml.ex index e9281b3ca153..53edc0a17b69 100644 --- a/apps/explorer/lib/explorer/visualize/sol2uml.ex +++ b/apps/explorer/lib/explorer/visualize/sol2uml.ex @@ -5,7 +5,7 @@ defmodule Explorer.Visualize.Sol2uml do alias HTTPoison.Response require Logger - @post_timeout :infinity + @post_timeout 60_000 @request_error_msg "Error while sending request to visualizer microservice" def visualize_contracts(body) do @@ -60,14 +60,7 @@ defmodule Explorer.Visualize.Sol2uml do def base_api_url, do: "#{base_url()}" <> "/api/v1" def base_url do - url = Application.get_env(:explorer, __MODULE__)[:service_url] - - if String.ends_with?(url, "/") do - url - |> String.slice(0..(String.length(url) - 2)) - else - url - end + Explorer.Utility.RustService.base_url(__MODULE__) end def enabled?, do: Application.get_env(:explorer, __MODULE__)[:enabled] From 1579071165515d012bbf6e61decf58a343922f96 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Thu, 24 Nov 2022 16:23:08 +0300 Subject: [PATCH 45/66] Add sol2uml env vars to makefile and docker-compose envs --- docker-compose/envs/common-blockscout.env | 2 ++ docker/Makefile | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env index b0d3c84156cf..7119152aed10 100644 --- a/docker-compose/envs/common-blockscout.env +++ b/docker-compose/envs/common-blockscout.env @@ -137,6 +137,8 @@ API_RATE_LIMIT_STATIC_API_KEY= FETCH_REWARDS_WAY=trace_block ENABLE_RUST_VERIFICATION_SERVICE=true RUST_VERIFICATION_SERVICE_URL=http://host.docker.internal:8043/ +VISUALIZE_SOL2UML_ENABLED=true +VISUALIZE_SOL2UML_VISUALIZE_SOL2UML_SERVICE_URL=http://host.docker.internal:8050/ # DATABASE_READ_ONLY_API_URL= # ACCOUNT_DATABASE_URL= # ACCOUNT_POOL_SIZE= diff --git a/docker/Makefile b/docker/Makefile index c38684bae11e..7c420a771018 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -550,6 +550,13 @@ endif ifdef ACCOUNT_CLOAK_KEY BLOCKSCOUT_CONTAINER_PARAMS += -e 'ACCOUNT_CLOAK_KEY=$(ACCOUNT_CLOAK_KEY)' endif +ifdef VISUALIZE_SOL2UML_ENABLED + BLOCKSCOUT_CONTAINER_PARAMS += -e 'VISUALIZE_SOL2UML_ENABLED=$(VISUALIZE_SOL2UML_ENABLED)' +endif +ifdef VISUALIZE_SOL2UML_SERVICE_URL + BLOCKSCOUT_CONTAINER_PARAMS += -e 'VISUALIZE_SOL2UML_SERVICE_URL=$(VISUALIZE_SOL2UML_SERVICE_URL)' +endif + HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep -sw "${BS_CONTAINER_IMAGE} ") build: From ae8e38d52d3d14270725d3871adec901b5bb9168 Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Thu, 24 Nov 2022 16:30:22 +0300 Subject: [PATCH 46/66] Fix mix credo --- .../lib/explorer/smart_contract/rust_verifier_interface.ex | 3 ++- apps/explorer/lib/explorer/utility/rust_service.ex | 3 +++ apps/explorer/lib/explorer/visualize/sol2uml.ex | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex b/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex index 8f3afb74c93b..ccca2505bc88 100644 --- a/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex +++ b/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex @@ -2,6 +2,7 @@ defmodule Explorer.SmartContract.RustVerifierInterface do @moduledoc """ Adapter for contracts verification with https://github.com/blockscout/blockscout-rs/blob/main/smart-contract-verifier """ + alias Explorer.Utility.RustService alias HTTPoison.Response require Logger @@ -137,7 +138,7 @@ defmodule Explorer.SmartContract.RustVerifierInterface do def base_api_url, do: "#{base_url()}" <> "/api/v1" def base_url do - Explorer.Utility.RustService.base_url(__MODULE__) + RustService.base_url(__MODULE__) end def enabled?, do: Application.get_env(:explorer, __MODULE__)[:enabled] diff --git a/apps/explorer/lib/explorer/utility/rust_service.ex b/apps/explorer/lib/explorer/utility/rust_service.ex index 97924a997567..63f949961252 100644 --- a/apps/explorer/lib/explorer/utility/rust_service.ex +++ b/apps/explorer/lib/explorer/utility/rust_service.ex @@ -1,4 +1,7 @@ defmodule Explorer.Utility.RustService do + @moduledoc """ + Module is responsible for common utils related to rust microservices. + """ def base_url(module) do url = Application.get_env(:explorer, module)[:service_url] diff --git a/apps/explorer/lib/explorer/visualize/sol2uml.ex b/apps/explorer/lib/explorer/visualize/sol2uml.ex index 53edc0a17b69..b507c63a2e10 100644 --- a/apps/explorer/lib/explorer/visualize/sol2uml.ex +++ b/apps/explorer/lib/explorer/visualize/sol2uml.ex @@ -2,6 +2,7 @@ defmodule Explorer.Visualize.Sol2uml do @moduledoc """ Adapter for sol2uml visualizer with https://github.com/blockscout/blockscout-rs/blob/main/visualizer """ + alias Explorer.Utility.RustService alias HTTPoison.Response require Logger @@ -60,7 +61,7 @@ defmodule Explorer.Visualize.Sol2uml do def base_api_url, do: "#{base_url()}" <> "/api/v1" def base_url do - Explorer.Utility.RustService.base_url(__MODULE__) + RustService.base_url(__MODULE__) end def enabled?, do: Application.get_env(:explorer, __MODULE__)[:enabled] From 3ad3ad49f82399352bce1a457124b173343fb30e Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Thu, 24 Nov 2022 18:40:22 +0300 Subject: [PATCH 47/66] Fix mix gettext --- apps/block_scout_web/priv/gettext/default.pot | 2 +- apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index ae907d6d85ed..6cfb1c37a8d3 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -1319,7 +1319,7 @@ msgstr "" msgid "For any existing contracts in the database, insert all ABI entries into the contract_methods table. Use this in case you have verified smart contracts before early March 2019 and you want other contracts with the same functions to show those ABI's as candidate matches." msgstr "" -#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:6 +#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:7 #, elixir-autogen, elixir-format msgid "For contract" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index ae907d6d85ed..6cfb1c37a8d3 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -1319,7 +1319,7 @@ msgstr "" msgid "For any existing contracts in the database, insert all ABI entries into the contract_methods table. Use this in case you have verified smart contracts before early March 2019 and you want other contracts with the same functions to show those ABI's as candidate matches." msgstr "" -#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:6 +#: lib/block_scout_web/templates/visualize_sol2uml/index.html.eex:7 #, elixir-autogen, elixir-format msgid "For contract" msgstr "" From 4b73d1170f3a18d611ff68abe564b53dcc59649d Mon Sep 17 00:00:00 2001 From: Lymarenko Lev Date: Sat, 26 Nov 2022 15:34:52 +0300 Subject: [PATCH 48/66] Add visualizer to docker-compose --- docker-compose/docker-compose-no-build-erigon.yml | 10 ++++++++++ docker-compose/docker-compose-no-build-ganache.yml | 9 +++++++++ docker-compose/docker-compose-no-build-geth.yml | 10 ++++++++++ .../docker-compose-no-build-hardhat-network.yml | 10 ++++++++++ docker-compose/docker-compose-no-build-nethermind.yml | 10 ++++++++++ .../docker-compose-no-build-no-db-container.yml | 10 ++++++++++ ...ication.yml => docker-compose-no-rust-services.yml} | 1 + docker-compose/docker-compose.yml | 9 +++++++++ docker-compose/envs/common-blockscout.env | 2 +- docker-compose/envs/common-visualizer.env | 1 + 10 files changed, 71 insertions(+), 1 deletion(-) rename docker-compose/{docker-compose-no-rust-verification.yml => docker-compose-no-rust-services.yml} (97%) create mode 100644 docker-compose/envs/common-visualizer.env diff --git a/docker-compose/docker-compose-no-build-erigon.yml b/docker-compose/docker-compose-no-build-erigon.yml index 5f3eb2a0122e..b1640627a815 100644 --- a/docker-compose/docker-compose-no-build-erigon.yml +++ b/docker-compose/docker-compose-no-build-erigon.yml @@ -58,3 +58,13 @@ services: - ./envs/common-smart-contract-verifier.env ports: - 8043:8043 + + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 + diff --git a/docker-compose/docker-compose-no-build-ganache.yml b/docker-compose/docker-compose-no-build-ganache.yml index 22442c15a98c..177d402e47bf 100644 --- a/docker-compose/docker-compose-no-build-ganache.yml +++ b/docker-compose/docker-compose-no-build-ganache.yml @@ -60,3 +60,12 @@ services: ports: - 8043:8043 + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 + diff --git a/docker-compose/docker-compose-no-build-geth.yml b/docker-compose/docker-compose-no-build-geth.yml index 0fd7caa74db8..116ee4afe79a 100644 --- a/docker-compose/docker-compose-no-build-geth.yml +++ b/docker-compose/docker-compose-no-build-geth.yml @@ -58,3 +58,13 @@ services: - ./envs/common-smart-contract-verifier.env ports: - 8043:8043 + + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 + diff --git a/docker-compose/docker-compose-no-build-hardhat-network.yml b/docker-compose/docker-compose-no-build-hardhat-network.yml index 9fabf5f3e185..3748696d8353 100644 --- a/docker-compose/docker-compose-no-build-hardhat-network.yml +++ b/docker-compose/docker-compose-no-build-hardhat-network.yml @@ -57,3 +57,13 @@ services: - ./envs/common-smart-contract-verifier.env ports: - 8043:8043 + + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 + diff --git a/docker-compose/docker-compose-no-build-nethermind.yml b/docker-compose/docker-compose-no-build-nethermind.yml index e5d607428012..300d63c8278d 100644 --- a/docker-compose/docker-compose-no-build-nethermind.yml +++ b/docker-compose/docker-compose-no-build-nethermind.yml @@ -58,3 +58,13 @@ services: - ./envs/common-smart-contract-verifier.env ports: - 8043:8043 + + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 + diff --git a/docker-compose/docker-compose-no-build-no-db-container.yml b/docker-compose/docker-compose-no-build-no-db-container.yml index 24295de00e3a..c73468c81cd0 100644 --- a/docker-compose/docker-compose-no-build-no-db-container.yml +++ b/docker-compose/docker-compose-no-build-no-db-container.yml @@ -41,3 +41,13 @@ services: - ./envs/common-smart-contract-verifier.env ports: - 8043:8043 + + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 + diff --git a/docker-compose/docker-compose-no-rust-verification.yml b/docker-compose/docker-compose-no-rust-services.yml similarity index 97% rename from docker-compose/docker-compose-no-rust-verification.yml rename to docker-compose/docker-compose-no-rust-services.yml index 287912e609e0..f0ede3f16325 100644 --- a/docker-compose/docker-compose-no-rust-verification.yml +++ b/docker-compose/docker-compose-no-rust-services.yml @@ -52,6 +52,7 @@ services: - ./envs/common-blockscout.env environment: ENABLE_RUST_VERIFICATION_SERVICE: 'false' + VISUALIZE_SOL2UML_ENABLED: 'false' ports: - 4000:4000 volumes: diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index 24b67343ac5c..63223524638b 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -64,3 +64,12 @@ services: - ./envs/common-smart-contract-verifier.env ports: - 8043:8043 + + visualizer: + image: ghcr.io/blockscout/visualizer:${VISUALIZER_DOCKER_TAG:-latest} + restart: always + container_name: 'visualizer' + env_file: + - ./envs/common-visualizer.env + ports: + - 8050:8050 diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env index 7119152aed10..73c936dbfa47 100644 --- a/docker-compose/envs/common-blockscout.env +++ b/docker-compose/envs/common-blockscout.env @@ -138,7 +138,7 @@ FETCH_REWARDS_WAY=trace_block ENABLE_RUST_VERIFICATION_SERVICE=true RUST_VERIFICATION_SERVICE_URL=http://host.docker.internal:8043/ VISUALIZE_SOL2UML_ENABLED=true -VISUALIZE_SOL2UML_VISUALIZE_SOL2UML_SERVICE_URL=http://host.docker.internal:8050/ +VISUALIZE_SOL2UML_SERVICE_URL=http://host.docker.internal:8050/ # DATABASE_READ_ONLY_API_URL= # ACCOUNT_DATABASE_URL= # ACCOUNT_POOL_SIZE= diff --git a/docker-compose/envs/common-visualizer.env b/docker-compose/envs/common-visualizer.env new file mode 100644 index 000000000000..b4fd470849cb --- /dev/null +++ b/docker-compose/envs/common-visualizer.env @@ -0,0 +1 @@ +VISUALIZER__SERVER__GRPC__ENABLED=false From f354a1e9f4812cc8bbb5a36bf031ff58c67745c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Fri, 25 Nov 2022 15:18:40 +0300 Subject: [PATCH 49/66] Split ordering cases for txs --- apps/explorer/lib/explorer/chain.ex | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 2ccb300b3e3e..a731bdea1642 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -439,7 +439,7 @@ defmodule Explorer.Chain do options |> Keyword.get(:paging_options, @default_paging_options) - |> fetch_transactions(from_block, to_block) + |> fetch_transactions(from_block, to_block, true) end defp transactions_block_numbers_at_address(address_hash, options) do @@ -4383,16 +4383,36 @@ defmodule Explorer.Chain do if Repo.one(query), do: true, else: false end - defp fetch_transactions(paging_options \\ nil, from_block \\ nil, to_block \\ nil) do + defp fetch_transactions(paging_options \\ nil, from_block \\ nil, to_block \\ nil, is_address? \\ false) do Transaction + |> order_for_transactions(paging_options, is_address?) + |> where_block_number_in_period(from_block, to_block) + |> handle_paging_options(paging_options) + end + + defp order_for_transactions(query, %PagingOptions{is_pending_tx: true}, true) do + query |> order_by([transaction], desc: transaction.block_number, desc: transaction.index, desc: transaction.inserted_at, desc: transaction.hash ) - |> where_block_number_in_period(from_block, to_block) - |> handle_paging_options(paging_options) + end + + defp order_for_transactions(query, %PagingOptions{key: nil}, true) do + query + |> order_by([transaction], + desc: transaction.block_number, + desc: transaction.index, + desc: transaction.inserted_at, + desc: transaction.hash + ) + end + + defp order_for_transactions(query, _, _) do + query + |> order_by([transaction], desc: transaction.block_number, desc: transaction.index) end defp fetch_transactions_in_ascending_order_by_index(paging_options) do From d40eee9057088a71a148cfa4744b267c533a4431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Sat, 26 Nov 2022 15:08:29 +0300 Subject: [PATCH 50/66] Add new indexes --- CHANGELOG.md | 2 +- .../20221126103223_add_txs_indexes.exs | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index e3bbcfbbdbc2..6933920f5db2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ - [#6473](https://github.com/blockscout/blockscout/pull/6473) - Fix state changes for contract creation transactions - [#6475](https://github.com/blockscout/blockscout/pull/6475) - Fix token name with unicode graphemes shortening - [#6420](https://github.com/blockscout/blockscout/pull/6420) - Fix address logs search -- [#6390](https://github.com/blockscout/blockscout/pull/6390), [#6502](https://github.com/blockscout/blockscout/pull/6502) - Fix transactions responses in API v2 +- [#6390](https://github.com/blockscout/blockscout/pull/6390), [#6502](https://github.com/blockscout/blockscout/pull/6502), [#6511](https://github.com/blockscout/blockscout/pull/6511) - Fix transactions responses in API v2 - [#6357](https://github.com/blockscout/blockscout/pull/6357), [#6409](https://github.com/blockscout/blockscout/pull/6409), [#6428](https://github.com/blockscout/blockscout/pull/6428) - Fix definitions of NETWORK_PATH, API_PATH, SOCKET_ROOT: process trailing slash - [#6338](https://github.com/blockscout/blockscout/pull/6338) - Fix token search with space - [#6329](https://github.com/blockscout/blockscout/pull/6329) - Prevent logger from truncating response from rust verifier service in case of an error diff --git a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs new file mode 100644 index 000000000000..c7799819c045 --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs @@ -0,0 +1,46 @@ +defmodule Explorer.Repo.Migrations.AddTxsIndexes do + use Ecto.Migration + @disable_ddl_transaction true + @disable_migration_lock true + + def change do + create( + index( + :transactions, + [ + :from_address_hash, + "block_number DESC NULLS FIRST", + "index DESC NULLS FIRST", + "inserted_at DESC", + "hash DESC" + ], + name: "transactions_from_address_hash_with_pending_index", + concurrently: true + ) + ) + + create( + index( + :transactions, + [:to_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", "inserted_at DESC", "hash DESC"], + name: "transactions_to_address_hash_with_pending_index", + concurrently: true + ) + ) + + create( + index( + :transactions, + [ + :created_contract_address_hash, + "block_number DESC NULLS FIRST", + "index DESC NULLS FIRST", + "inserted_at DESC", + "hash DESC" + ], + name: "transactions_created_contract_address_hash_with_pending_index", + concurrently: true + ) + ) + end +end From a63db41206176a3c9c9d8f2b24ef6515ec170afc Mon Sep 17 00:00:00 2001 From: nikitosing <32202610+nikitosing@users.noreply.github.com> Date: Mon, 28 Nov 2022 14:34:13 +0300 Subject: [PATCH 51/66] Smart contract verification improvements (#6481) * Refactor smart contract verification form; Add support for smart contract verification without creation bytecode * Add compiler settings for smart contracts verified via standard JSON input or Sourcify * Add verified twin name as fallback name for unverified contract; Fix compiler label --- .dialyzer-ignore | 2 +- CHANGELOG.md | 1 + .../templates/address_contract/index.html.eex | 17 +++- .../_compiler_field.html.eex | 2 +- .../_fetch_constructor_args.html.eex | 6 +- .../_include_nightly_builds_field.html.eex | 34 ++++---- .../_libraries_other.html.eex | 9 +- .../_library_address.html.eex | 8 +- .../_library_first.html.eex | 18 ++-- .../_library_name.html.eex | 14 +-- .../_yul_contracts_switcher.html.eex | 4 +- .../new.html.eex | 8 +- .../new.html.eex | 10 +-- .../new.html.eex | 2 +- .../lib/block_scout_web/views/address_view.ex | 19 ++-- .../views/api/rpc/contract_view.ex | 12 +++ apps/block_scout_web/priv/gettext/default.pot | 87 ++++++++++++------- .../priv/gettext/en/LC_MESSAGES/default.po | 87 ++++++++++++------- apps/explorer/lib/explorer/chain.ex | 44 ++++++---- .../lib/explorer/chain/smart_contract.ex | 6 +- .../smart_contract/rust_verifier_interface.ex | 6 +- .../smart_contract/solidity/publisher.ex | 30 ++++++- .../smart_contract/solidity/verifier.ex | 1 + .../third_party_integrations/sourcify.ex | 1 + ...21120184715_add_json_compiler_settings.exs | 9 ++ 25 files changed, 287 insertions(+), 150 deletions(-) create mode 100644 apps/explorer/priv/repo/migrations/20221120184715_add_json_compiler_settings.exs diff --git a/.dialyzer-ignore b/.dialyzer-ignore index 7c287bf3b506..73a7edec27db 100644 --- a/.dialyzer-ignore +++ b/.dialyzer-ignore @@ -22,7 +22,7 @@ lib/explorer/smart_contract/reader.ex:435 lib/indexer/fetcher/token_total_supply_on_demand.ex:16 lib/explorer/exchange_rates/source.ex:116 lib/explorer/exchange_rates/source.ex:119 -lib/explorer/smart_contract/solidity/verifier.ex:316 +lib/explorer/smart_contract/solidity/verifier.ex:317 lib/block_scout_web/templates/address_contract/index.html.eex:158 lib/block_scout_web/templates/address_contract/index.html.eex:195 lib/explorer/third_party_integrations/sourcify.ex:120 diff --git a/CHANGELOG.md b/CHANGELOG.md index e3bbcfbbdbc2..8b864ff6b0a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - [#6401](https://github.com/blockscout/blockscout/pull/6401) - Add Sol2Uml contract visualization +- [#6481](https://github.com/blockscout/blockscout/pull/6481) - Smart contract verification improvements - [#6444](https://github.com/blockscout/blockscout/pull/6444) - Add support for yul verification via rust microservice - [#6440](https://github.com/blockscout/blockscout/pull/6440) - Add support for base64 encoded NFT metadata - [#6407](https://github.com/blockscout/blockscout/pull/6407) - Indexed ratio for int txs fetching stage diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex index 86e9f64cd6e2..63b350a958f8 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex @@ -131,7 +131,22 @@
<% end)%> - <%= if !is_nil(target_contract.abi) do %>> + <%= if !is_nil(target_contract.compiler_settings) do %> +
+
+

<%= gettext "Compiler Settings" %>

+ +
+
+
<%= format_smart_contract_abi(target_contract.compiler_settings) %>
+              
+
+
+ <% end %> + + <%= if !is_nil(target_contract.abi) do %>

<%= gettext "Contract ABI" %>

diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_compiler_field.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_compiler_field.html.eex index fd98aaf149e9..bd2a179d80ee 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_compiler_field.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_compiler_field.html.eex @@ -1,6 +1,6 @@
- <%= label @f, :compiler_version, gettext("Compiler") %> + <%= label :smart_contract, :compiler_version, gettext("Compiler") %>
<%= select @f, :compiler_version, @compiler_versions, class: "form-control border-rounded", "aria-describedby": "compiler-help-block", id: "smart_contract_compiler_version" %> <%= error_tag @f, :compiler_version, id: "compiler-help-block", class: "text-danger form-error" %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex index fcc2109fc373..c269a84e79a1 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex @@ -1,17 +1,17 @@
- <%= label @f, "Try to fetch constructor arguments automatically" %> + <%= label @f, :autodetect_constructor_args, gettext("Try to fetch constructor arguments automatically") %>
<%= radio_button @f, :autodetect_constructor_args, false, class: "form-check-input autodetectfalse" %>
- <%= label :autodetect_constructor_args, :false, gettext("No"), class: "radio-text" %> + <%= label @f, :autodetect_constructor_args_false, gettext("No"), class: "radio-text" %>
<%= radio_button @f, :autodetect_constructor_args, true, class: "form-check-input autodetecttrue", "aria-describedby": "autodetect_constructor_args-help-block" %>
- <%= label :autodetect_constructor_args, :true, gettext("Yes"), class: "radio-text" %> + <%= label @f, :autodetect_constructor_args_true, gettext("Yes"), class: "radio-text" %>
<%= error_tag @f, :autodetect_constructor_args, id: "autodetect_constructor_args-help-block", class: "text-danger form-error" %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex index 275de35cbec9..c452549a7069 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex @@ -1,21 +1,21 @@
-
- <%= label @f, "Include nightly builds" %> -
-
-
- <%= radio_button @f, :nightly_builds, false, checked: true, class: "form-check-input nightly-builds-false" %> -
- <%= label :nightly_builds, :false, gettext("No"), class: "radio-text" %> -
-
- <%= radio_button @f, :nightly_builds, true, class: "form-check-input nightly-builds-true", "aria-describedby": "nightly_builds-help-block" %> -
- <%= label :nightly_builds, :true, gettext("Yes"), class: "radio-text" %> -
-
- <%= error_tag @f, :nightly_builds, id: "nightly_builds-help-block", class: "text-danger form-error" %> +
+ <%= label @f, :nightly_builds, gettext("Include nightly builds") %> +
+
+
+ <%= radio_button @f, :nightly_builds, false, checked: true, class: "form-check-input nightly-builds-false" %> +
+ <%= label @f, :nightly_builds_false, gettext("No"), class: "radio-text" %> +
+
+ <%= radio_button @f, :nightly_builds, true, class: "form-check-input nightly-builds-true", "aria-describedby": "nightly_builds-help-block" %> +
+ <%= label @f, :nightly_builds_true, gettext("Yes"), class: "radio-text" %>
-
Select yes if you want to show nightly builds.
+
+ <%= error_tag @f, :nightly_builds, id: "nightly_builds-help-block", class: "text-danger form-error" %>
+
<%= gettext("Select yes if you want to show nightly builds.") %>
+
\ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_libraries_other.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_libraries_other.html.eex index 7c6af84faf51..104730d49a27 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_libraries_other.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_libraries_other.html.eex @@ -1,8 +1,7 @@ <%= for library_index <- 2..Application.get_env(:block_scout_web, :verification_max_libraries) do %> - <% library = "library" <> to_string(library_index) |> String.to_atom() %> -
- <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_name.html", library: library, index: library_index %> +
+ <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_name.html", index: library_index %> - <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_address.html", library: library, index: library_index %> -
+ <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_address.html", index: library_index %> +
<% end %> \ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex index e86bb67efad3..914518876a72 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_address.html.eex @@ -1,10 +1,10 @@ <% library_address = "library" <> to_string(@index) <> "_address" |> String.to_atom() %>
-
- <%= label :external_libraries, @library, gettext("Library") <> " " <> to_string(@index) <> " " <> gettext("Address") %> +
+ <%= label :external_libraries, library_address, gettext("Library") <> " " <> to_string(@index) <> " " <> gettext("Address") %>
- <%= text_input :external_libraries, library_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %> + <%= text_input :external_libraries, library_address, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %>
<%= if assigns[:tooltip_text] do @tooltip_text end %>
-
+
\ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex index 995d86cf9cc0..adb38c4d7c16 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex @@ -1,13 +1,11 @@
- <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_name.html", - library: :library1, - index: 1, - tooltip_text: gettext("A library name called in the .sol file. Multiple libraries (up to ") <> to_string(Application.get_env(:block_scout_web, :verification_max_libraries)) <> gettext(") may be added for each contract. Click the Add Library button to add an additional one.") - %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_name.html", + index: 1, + tooltip_text: gettext("A library name called in the .sol file. Multiple libraries (up to ") <> to_string(Application.get_env(:block_scout_web, :verification_max_libraries)) <> gettext(") may be added for each contract. Click the Add Library button to add an additional one.") + %> - <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_address.html", - library: :library1, - index: 1, - tooltip_text: gettext "The 0x library address. This can be found in the generated json file or Truffle output (if using truffle)." - %> + <%= render BlockScoutWeb.AddressContractVerificationCommonFieldsView, "_library_address.html", + index: 1, + tooltip_text: gettext "The 0x library address. This can be found in the generated json file or Truffle output (if using truffle)." + %>
\ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex index b1e0a7a5e0a3..fc15114a6294 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_library_name.html.eex @@ -1,10 +1,10 @@ <% library_name = "library" <> to_string(@index) <> "_name" |> String.to_atom() %>
-
- <%= label :external_libraries, @library, gettext("Library") <> " " <> to_string(@index) <> " " <> gettext("Name") %> -
- <%= text_input :external_libraries, library_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %> -
-
<%= if assigns[:tooltip_text] do @tooltip_text end %>
-
+
+ <%= label :external_libraries, library_name, gettext("Library") <> " " <> to_string(@index) <> " " <> gettext("Name") %> +
+ <%= text_input :external_libraries, library_name, class: "form-control border-rounded", "aria-describedby": "contract-name-help-block" %> +
+
<%= if assigns[:tooltip_text] do @tooltip_text end %>
+
\ No newline at end of file diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex index ce83d4d47e5d..8dd4bdebf564 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_common_fields/_yul_contracts_switcher.html.eex @@ -6,12 +6,12 @@
<%= radio_button @f, :is_yul, false, class: "form-check-input autodetectfalse" %>
- <%= label :is_yul, :false, gettext("No"), class: "radio-text" %> + <%= label @f, :is_yul_false, gettext("No"), class: "radio-text" %>
<%= radio_button @f, :is_yul, true, class: "form-check-input autodetecttrue", "aria-describedby": "is_yul-help-block" %>
- <%= label :is_yul, :true, gettext("Yes"), class: "radio-text" %> + <%= label @f, :is_yul_true, gettext("Yes"), class: "radio-text" %>
<%= error_tag @f, :is_yul, id: "is_yul-help-block", class: "text-danger form-error" %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex index 9eec8b7d7ba0..383aa4584d4c 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex @@ -1,6 +1,6 @@ <% metadata_for_verification = if assigns[:retrying], do: nil, else: Chain.get_address_verified_twin_contract(@address_hash).verified_contract %> <% changeset = (if assigns[:retrying], do: @changeset, else: SmartContract.merge_twin_contract_with_changeset(metadata_for_verification, @changeset)) |> SmartContract.address_to_checksum_address() %> -<% fetch_constructor_arguments_automatically = if metadata_for_verification, do: true, else: changeset.changes.autodetect_constructor_args %> +<% fetch_constructor_arguments_automatically = if metadata_for_verification, do: true, else: changeset.changes[:autodetect_constructor_args] || true %> <% display_constructor_arguments_text_area = if fetch_constructor_arguments_automatically, do: "none", else: "block" %>
<%= render BlockScoutWeb.CommonComponentsView, "_channel_disconnected_message.html", text: gettext("Connection Lost") %> @@ -27,7 +27,7 @@
- <%= label :evm_version, :evm_version, gettext("EVM Version") %> + <%= label f, :evm_version, gettext("EVM Version") %>
<%= select f, :evm_version, @evm_versions, class: "form-control border-rounded", "aria-describedby": "evm-version-help-block" %>
@@ -37,7 +37,7 @@
- <%= label f, "Optimization" %> + <%= label f, :optimization, gettext("Optimization") %>
@@ -59,7 +59,7 @@
">
- <%= label f, :name, gettext("Optimization runs") %> + <%= label f, :optimization_runs, gettext("Optimization runs") %>
<%= text_input f, :optimization_runs, class: "form-control border-rounded", "aria-describedby": "optimization-runs-help-block", "data-test": "optimization-runs" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex index c5a9e46819d5..2b2950397e8e 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex @@ -19,7 +19,7 @@
- <%= label :evm_version, :evm_version, gettext("EVM Version") %> + <%= label f, :evm_version, gettext("EVM Version") %>
<%= select f, :evm_version, @evm_versions, class: "form-control border-rounded", "aria-describedby": "evm-version-help-block" %>
@@ -29,18 +29,18 @@
- <%= label f, "Optimization" %> + <%= label f, :optimization, gettext("Optimization") %>
<%= radio_button f, :optimization, false, class: "form-check-input optimization-false" %>
- <%= label :smart_contract_optimization, :false, gettext("No"), class: "radio-text" %> + <%= label f, :optimization_false, gettext("No"), class: "radio-text" %>
<%= radio_button f, :optimization, true, class: "form-check-input optimization-true", "aria-describedby": "optimization-help-block" %>
- <%= label :smart_contract_optimization, :true, gettext("Yes"), class: "radio-text" %> + <%= label f, :optimization_true, gettext("Yes"), class: "radio-text" %>
<%= error_tag f, :optimization, id: "optimization-help-block", class: "text-danger form-error" %> @@ -51,7 +51,7 @@
">
- <%= label f, :name, gettext("Optimization runs") %> + <%= label f, :optimization_runs, gettext("Optimization runs") %>
<%= text_input f, :optimization_runs, class: "form-control border-rounded", "aria-describedby": "optimization-runs-help-block", "data-test": "optimization-runs" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex index e86c15880e60..9eb3c96ea58a 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract_verification_via_standard_json_input/new.html.eex @@ -1,6 +1,6 @@ <% metadata_for_verification = Chain.get_address_verified_twin_contract(@address_hash).verified_contract %> <% changeset = (if assigns[:retrying], do: @changeset, else: SmartContract.merge_twin_contract_with_changeset(metadata_for_verification, @changeset)) |> SmartContract.address_to_checksum_address() %> -<% fetch_constructor_arguments_automatically = if metadata_for_verification, do: true, else: changeset.changes.autodetect_constructor_args %> +<% fetch_constructor_arguments_automatically = if metadata_for_verification, do: true, else: changeset.changes[:autodetect_constructor_args] || true %> <% display_constructor_arguments_text_area = if fetch_constructor_arguments_automatically, do: "none", else: "block" %>
<%= render BlockScoutWeb.CommonComponentsView, "_channel_disconnected_message.html", text: gettext("Connection Lost") %> diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex index 50f54e6b2bea..b1d184959862 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex @@ -181,9 +181,7 @@ defmodule BlockScoutWeb.AddressView do @doc """ Returns the primary name of an address if available. If there is no names on address function performs preload of names association. """ - def primary_name(_, second_time? \\ false) - - def primary_name(%Address{names: [_ | _] = address_names}, _second_time?) do + def primary_name(%Address{names: [_ | _] = address_names}) do case Enum.find(address_names, &(&1.primary == true)) do nil -> %Address.Name{name: name} = Enum.at(address_names, 0) @@ -194,11 +192,20 @@ defmodule BlockScoutWeb.AddressView do end end - def primary_name(%Address{names: _} = address, false) do - primary_name(Repo.preload(address, [:names]), true) + def primary_name(%Address{names: %Ecto.Association.NotLoaded{}} = address) do + primary_name(Repo.preload(address, [:names])) end - def primary_name(%Address{names: _}, true), do: nil + def primary_name(%Address{names: _} = address) do + with false <- is_nil(address.contract_code), + twin <- Chain.get_verified_twin_contract(address), + false <- is_nil(twin) do + twin.name + else + _ -> + nil + end + end def implementation_name(%Address{smart_contract: %{implementation_name: implementation_name}}), do: implementation_name diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex index ace6af7517b1..d1686cef1565 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/contract_view.ex @@ -52,6 +52,18 @@ defmodule BlockScoutWeb.API.RPC.ContractView do |> set_external_libraries(contract) |> set_verified_contract_data(contract, address, optimization) |> set_proxy_info(contract) + |> set_compiler_settings(contract) + end + + defp set_compiler_settings(contract_output, contract) when contract == %{}, do: contract_output + + defp set_compiler_settings(contract_output, contract) do + if is_nil(contract.compiler_settings) do + contract_output + else + contract_output + |> Map.put(:CompilerSettings, contract.compiler_settings) + end end defp set_proxy_info(contract_output, contract) when contract == %{} do diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 6cfb1c37a8d3..b1258df630b5 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -76,7 +76,7 @@ msgstr "" msgid "(query)" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:4 #, elixir-autogen, elixir-format msgid ") may be added for each contract. Click the Add Library button to add an additional one." msgstr "" @@ -97,7 +97,7 @@ msgstr "" msgid "A block producer who successfully included the block onto the blockchain." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:4 #, elixir-autogen, elixir-format msgid "A library name called in the .sol file. Multiple libraries (up to " msgstr "" @@ -493,7 +493,7 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:48 #: lib/block_scout_web/templates/address/overview.html.eex:276 #: lib/block_scout_web/templates/address_validation/index.html.eex:11 -#: lib/block_scout_web/views/address_view.ex:374 +#: lib/block_scout_web/views/address_view.ex:381 #, elixir-autogen, elixir-format msgid "Blocks Validated" msgstr "" @@ -588,13 +588,13 @@ msgstr "" #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187 #: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126 #: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149 -#: lib/block_scout_web/views/address_view.ex:367 +#: lib/block_scout_web/views/address_view.ex:374 #, elixir-autogen, elixir-format msgid "Code" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:34 -#: lib/block_scout_web/views/address_view.ex:373 +#: lib/block_scout_web/views/address_view.ex:380 #, elixir-autogen, elixir-format msgid "Coin Balance History" msgstr "" @@ -690,7 +690,7 @@ msgstr "" msgid "Contract" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:137 +#: lib/block_scout_web/templates/address_contract/index.html.eex:152 #, elixir-autogen, elixir-format msgid "Contract ABI" msgstr "" @@ -720,8 +720,8 @@ msgstr "" msgid "Contract Creation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:154 #: lib/block_scout_web/templates/address_contract/index.html.eex:169 +#: lib/block_scout_web/templates/address_contract/index.html.eex:184 #, elixir-autogen, elixir-format msgid "Contract Creation Code" msgstr "" @@ -769,7 +769,7 @@ msgstr "" msgid "Contracts" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:160 +#: lib/block_scout_web/templates/address_contract/index.html.eex:175 #, elixir-autogen, elixir-format msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -779,7 +779,7 @@ msgstr "" msgid "Contribute" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:139 +#: lib/block_scout_web/templates/address_contract/index.html.eex:154 #, elixir-autogen, elixir-format msgid "Copy ABI" msgstr "" @@ -811,8 +811,8 @@ msgstr "" msgid "Copy Contract Address" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:156 -#: lib/block_scout_web/templates/address_contract/index.html.eex:172 +#: lib/block_scout_web/templates/address_contract/index.html.eex:171 +#: lib/block_scout_web/templates/address_contract/index.html.eex:187 #, elixir-autogen, elixir-format msgid "Copy Contract Creation Code" msgstr "" @@ -822,8 +822,8 @@ msgstr "" msgid "Copy Decompiled Contract Code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:193 -#: lib/block_scout_web/templates/address_contract/index.html.eex:203 +#: lib/block_scout_web/templates/address_contract/index.html.eex:208 +#: lib/block_scout_web/templates/address_contract/index.html.eex:218 #, elixir-autogen, elixir-format msgid "Copy Deployed ByteCode" msgstr "" @@ -1006,7 +1006,7 @@ msgstr "" msgid "Decoded" msgstr "" -#: lib/block_scout_web/views/address_view.ex:368 +#: lib/block_scout_web/views/address_view.ex:375 #, elixir-autogen, elixir-format msgid "Decompiled Code" msgstr "" @@ -1031,8 +1031,8 @@ msgstr "" msgid "Delegate Call" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:191 -#: lib/block_scout_web/templates/address_contract/index.html.eex:199 +#: lib/block_scout_web/templates/address_contract/index.html.eex:206 +#: lib/block_scout_web/templates/address_contract/index.html.eex:214 #, elixir-autogen, elixir-format msgid "Deployed ByteCode" msgstr "" @@ -1062,7 +1062,7 @@ msgstr "" msgid "Difficulty" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:161 +#: lib/block_scout_web/templates/address_contract/index.html.eex:176 #, elixir-autogen, elixir-format msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1260,7 +1260,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:228 +#: lib/block_scout_web/templates/address_contract/index.html.eex:243 #, elixir-autogen, elixir-format msgid "External libraries" msgstr "" @@ -1515,7 +1515,7 @@ msgstr "" #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:17 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:11 #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6 -#: lib/block_scout_web/views/address_view.ex:364 +#: lib/block_scout_web/views/address_view.ex:371 #: lib/block_scout_web/views/transaction_view.ex:510 #, elixir-autogen, elixir-format msgid "Internal Transactions" @@ -1637,7 +1637,7 @@ msgstr "" #: lib/block_scout_web/templates/address_logs/index.html.eex:10 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:17 #: lib/block_scout_web/templates/transaction_log/index.html.eex:8 -#: lib/block_scout_web/views/address_view.ex:375 +#: lib/block_scout_web/views/address_view.ex:382 #: lib/block_scout_web/views/transaction_view.ex:511 #, elixir-autogen, elixir-format msgid "Logs" @@ -1910,6 +1910,8 @@ msgstr "" msgid "Only the first" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:40 +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:32 #: lib/block_scout_web/templates/verified_contracts/index.html.eex:69 #, elixir-autogen, elixir-format msgid "Optimization" @@ -2111,7 +2113,7 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:81 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27 -#: lib/block_scout_web/views/address_view.ex:369 +#: lib/block_scout_web/views/address_view.ex:376 #: lib/block_scout_web/views/tokens/overview_view.ex:41 #, elixir-autogen, elixir-format msgid "Read Contract" @@ -2119,7 +2121,7 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:88 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41 -#: lib/block_scout_web/views/address_view.ex:370 +#: lib/block_scout_web/views/address_view.ex:377 #, elixir-autogen, elixir-format msgid "Read Proxy" msgstr "" @@ -2431,7 +2433,7 @@ msgstr "" msgid "Test Networks" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:11 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:9 #, elixir-autogen, elixir-format msgid "The 0x library address. This can be found in the generated json file or Truffle output (if using truffle)." msgstr "" @@ -2755,7 +2757,7 @@ msgstr "" #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:15 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:4 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7 -#: lib/block_scout_web/views/address_view.ex:366 +#: lib/block_scout_web/views/address_view.ex:373 #: lib/block_scout_web/views/tokens/instance/overview_view.ex:197 #: lib/block_scout_web/views/tokens/overview_view.ex:39 #: lib/block_scout_web/views/transaction_view.ex:509 @@ -2779,7 +2781,7 @@ msgstr "" #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13 #: lib/block_scout_web/templates/layout/_topnav.html.eex:78 #: lib/block_scout_web/templates/tokens/index.html.eex:10 -#: lib/block_scout_web/views/address_view.ex:363 +#: lib/block_scout_web/views/address_view.ex:370 #, elixir-autogen, elixir-format msgid "Tokens" msgstr "" @@ -2941,7 +2943,7 @@ msgstr "" #: lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: lib/block_scout_web/templates/chain/show.html.eex:213 #: lib/block_scout_web/templates/layout/_topnav.html.eex:49 -#: lib/block_scout_web/views/address_view.ex:365 +#: lib/block_scout_web/views/address_view.ex:372 #, elixir-autogen, elixir-format msgid "Transactions" msgstr "" @@ -3124,8 +3126,8 @@ msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:28 #: lib/block_scout_web/templates/address_contract/index.html.eex:30 -#: lib/block_scout_web/templates/address_contract/index.html.eex:177 -#: lib/block_scout_web/templates/address_contract/index.html.eex:208 +#: lib/block_scout_web/templates/address_contract/index.html.eex:192 +#: lib/block_scout_web/templates/address_contract/index.html.eex:223 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 #, elixir-autogen, elixir-format msgid "Verify & Publish" @@ -3285,14 +3287,14 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:95 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34 -#: lib/block_scout_web/views/address_view.ex:371 +#: lib/block_scout_web/views/address_view.ex:378 #, elixir-autogen, elixir-format msgid "Write Contract" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:102 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48 -#: lib/block_scout_web/views/address_view.ex:372 +#: lib/block_scout_web/views/address_view.ex:379 #, elixir-autogen, elixir-format msgid "Write Proxy" msgstr "" @@ -3461,3 +3463,28 @@ msgstr "" #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Include nightly builds" +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select yes if you want to show nightly builds." +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Try to fetch constructor arguments automatically" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:137 +#, elixir-autogen, elixir-format +msgid "Compiler Settings" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:139 +#, elixir-autogen, elixir-format +msgid "Copy Compiler Settings" +msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index 6cfb1c37a8d3..b5d53aba9021 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -76,7 +76,7 @@ msgstr "" msgid "(query)" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:4 #, elixir-autogen, elixir-format msgid ") may be added for each contract. Click the Add Library button to add an additional one." msgstr "" @@ -97,7 +97,7 @@ msgstr "" msgid "A block producer who successfully included the block onto the blockchain." msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:5 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:4 #, elixir-autogen, elixir-format msgid "A library name called in the .sol file. Multiple libraries (up to " msgstr "" @@ -493,7 +493,7 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:48 #: lib/block_scout_web/templates/address/overview.html.eex:276 #: lib/block_scout_web/templates/address_validation/index.html.eex:11 -#: lib/block_scout_web/views/address_view.ex:374 +#: lib/block_scout_web/views/address_view.ex:381 #, elixir-autogen, elixir-format msgid "Blocks Validated" msgstr "" @@ -588,13 +588,13 @@ msgstr "" #: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187 #: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126 #: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149 -#: lib/block_scout_web/views/address_view.ex:367 +#: lib/block_scout_web/views/address_view.ex:374 #, elixir-autogen, elixir-format msgid "Code" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:34 -#: lib/block_scout_web/views/address_view.ex:373 +#: lib/block_scout_web/views/address_view.ex:380 #, elixir-autogen, elixir-format msgid "Coin Balance History" msgstr "" @@ -690,7 +690,7 @@ msgstr "" msgid "Contract" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:137 +#: lib/block_scout_web/templates/address_contract/index.html.eex:152 #, elixir-autogen, elixir-format msgid "Contract ABI" msgstr "" @@ -720,8 +720,8 @@ msgstr "" msgid "Contract Creation" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:154 #: lib/block_scout_web/templates/address_contract/index.html.eex:169 +#: lib/block_scout_web/templates/address_contract/index.html.eex:184 #, elixir-autogen, elixir-format msgid "Contract Creation Code" msgstr "" @@ -769,7 +769,7 @@ msgstr "" msgid "Contracts" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:160 +#: lib/block_scout_web/templates/address_contract/index.html.eex:175 #, elixir-autogen, elixir-format msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified." msgstr "" @@ -779,7 +779,7 @@ msgstr "" msgid "Contribute" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:139 +#: lib/block_scout_web/templates/address_contract/index.html.eex:154 #, elixir-autogen, elixir-format msgid "Copy ABI" msgstr "" @@ -811,8 +811,8 @@ msgstr "" msgid "Copy Contract Address" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:156 -#: lib/block_scout_web/templates/address_contract/index.html.eex:172 +#: lib/block_scout_web/templates/address_contract/index.html.eex:171 +#: lib/block_scout_web/templates/address_contract/index.html.eex:187 #, elixir-autogen, elixir-format msgid "Copy Contract Creation Code" msgstr "" @@ -822,8 +822,8 @@ msgstr "" msgid "Copy Decompiled Contract Code" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:193 -#: lib/block_scout_web/templates/address_contract/index.html.eex:203 +#: lib/block_scout_web/templates/address_contract/index.html.eex:208 +#: lib/block_scout_web/templates/address_contract/index.html.eex:218 #, elixir-autogen, elixir-format msgid "Copy Deployed ByteCode" msgstr "" @@ -1006,7 +1006,7 @@ msgstr "" msgid "Decoded" msgstr "" -#: lib/block_scout_web/views/address_view.ex:368 +#: lib/block_scout_web/views/address_view.ex:375 #, elixir-autogen, elixir-format msgid "Decompiled Code" msgstr "" @@ -1031,8 +1031,8 @@ msgstr "" msgid "Delegate Call" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:191 -#: lib/block_scout_web/templates/address_contract/index.html.eex:199 +#: lib/block_scout_web/templates/address_contract/index.html.eex:206 +#: lib/block_scout_web/templates/address_contract/index.html.eex:214 #, elixir-autogen, elixir-format msgid "Deployed ByteCode" msgstr "" @@ -1062,7 +1062,7 @@ msgstr "" msgid "Difficulty" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:161 +#: lib/block_scout_web/templates/address_contract/index.html.eex:176 #, elixir-autogen, elixir-format msgid "Displaying the init data provided of the creating transaction." msgstr "" @@ -1260,7 +1260,7 @@ msgstr "" msgid "Export Data" msgstr "" -#: lib/block_scout_web/templates/address_contract/index.html.eex:228 +#: lib/block_scout_web/templates/address_contract/index.html.eex:243 #, elixir-autogen, elixir-format msgid "External libraries" msgstr "" @@ -1515,7 +1515,7 @@ msgstr "" #: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:17 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:11 #: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6 -#: lib/block_scout_web/views/address_view.ex:364 +#: lib/block_scout_web/views/address_view.ex:371 #: lib/block_scout_web/views/transaction_view.ex:510 #, elixir-autogen, elixir-format msgid "Internal Transactions" @@ -1637,7 +1637,7 @@ msgstr "" #: lib/block_scout_web/templates/address_logs/index.html.eex:10 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:17 #: lib/block_scout_web/templates/transaction_log/index.html.eex:8 -#: lib/block_scout_web/views/address_view.ex:375 +#: lib/block_scout_web/views/address_view.ex:382 #: lib/block_scout_web/views/transaction_view.ex:511 #, elixir-autogen, elixir-format msgid "Logs" @@ -1910,6 +1910,8 @@ msgstr "" msgid "Only the first" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_via_flattened_code/new.html.eex:40 +#: lib/block_scout_web/templates/address_contract_verification_via_multi_part_files/new.html.eex:32 #: lib/block_scout_web/templates/verified_contracts/index.html.eex:69 #, elixir-autogen, elixir-format msgid "Optimization" @@ -2111,7 +2113,7 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:81 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27 -#: lib/block_scout_web/views/address_view.ex:369 +#: lib/block_scout_web/views/address_view.ex:376 #: lib/block_scout_web/views/tokens/overview_view.ex:41 #, elixir-autogen, elixir-format msgid "Read Contract" @@ -2119,7 +2121,7 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:88 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41 -#: lib/block_scout_web/views/address_view.ex:370 +#: lib/block_scout_web/views/address_view.ex:377 #, elixir-autogen, elixir-format msgid "Read Proxy" msgstr "" @@ -2431,7 +2433,7 @@ msgstr "" msgid "Test Networks" msgstr "" -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:11 +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_library_first.html.eex:9 #, elixir-autogen, elixir-format msgid "The 0x library address. This can be found in the generated json file or Truffle output (if using truffle)." msgstr "" @@ -2755,7 +2757,7 @@ msgstr "" #: lib/block_scout_web/templates/tokens/transfer/index.html.eex:15 #: lib/block_scout_web/templates/transaction/_tabs.html.eex:4 #: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7 -#: lib/block_scout_web/views/address_view.ex:366 +#: lib/block_scout_web/views/address_view.ex:373 #: lib/block_scout_web/views/tokens/instance/overview_view.ex:197 #: lib/block_scout_web/views/tokens/overview_view.ex:39 #: lib/block_scout_web/views/transaction_view.ex:509 @@ -2779,7 +2781,7 @@ msgstr "" #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13 #: lib/block_scout_web/templates/layout/_topnav.html.eex:78 #: lib/block_scout_web/templates/tokens/index.html.eex:10 -#: lib/block_scout_web/views/address_view.ex:363 +#: lib/block_scout_web/views/address_view.ex:370 #, elixir-autogen, elixir-format msgid "Tokens" msgstr "" @@ -2941,7 +2943,7 @@ msgstr "" #: lib/block_scout_web/templates/block_transaction/index.html.eex:10 #: lib/block_scout_web/templates/chain/show.html.eex:213 #: lib/block_scout_web/templates/layout/_topnav.html.eex:49 -#: lib/block_scout_web/views/address_view.ex:365 +#: lib/block_scout_web/views/address_view.ex:372 #, elixir-autogen, elixir-format msgid "Transactions" msgstr "" @@ -3124,8 +3126,8 @@ msgstr "" #: lib/block_scout_web/templates/address_contract/index.html.eex:28 #: lib/block_scout_web/templates/address_contract/index.html.eex:30 -#: lib/block_scout_web/templates/address_contract/index.html.eex:177 -#: lib/block_scout_web/templates/address_contract/index.html.eex:208 +#: lib/block_scout_web/templates/address_contract/index.html.eex:192 +#: lib/block_scout_web/templates/address_contract/index.html.eex:223 #: lib/block_scout_web/templates/smart_contract/_functions.html.eex:14 #, elixir-autogen, elixir-format msgid "Verify & Publish" @@ -3285,14 +3287,14 @@ msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:95 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34 -#: lib/block_scout_web/views/address_view.ex:371 +#: lib/block_scout_web/views/address_view.ex:378 #, elixir-autogen, elixir-format msgid "Write Contract" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:102 #: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48 -#: lib/block_scout_web/views/address_view.ex:372 +#: lib/block_scout_web/views/address_view.ex:379 #, elixir-autogen, elixir-format msgid "Write Proxy" msgstr "" @@ -3461,3 +3463,28 @@ msgstr "" #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Include nightly builds" +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select yes if you want to show nightly builds." +msgstr "" + +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Try to fetch constructor arguments automatically" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:137 +#, elixir-autogen, elixir-format, fuzzy +msgid "Compiler Settings" +msgstr "" + +#: lib/block_scout_web/templates/address_contract/index.html.eex:139 +#, elixir-autogen, elixir-format +msgid "Copy Compiler Settings" +msgstr "" diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 2ccb300b3e3e..bf4cff852cad 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -4203,6 +4203,30 @@ defmodule Explorer.Chain do |> repo.insert(on_conflict: :nothing, conflict_target: [:address_hash, :name]) end + def get_verified_twin_contract(%Explorer.Chain.Address{} = target_address) do + case target_address do + %{contract_code: %Chain.Data{bytes: contract_code_bytes}} -> + target_address_hash = target_address.hash + + contract_code_md5 = Helper.contract_code_md5(contract_code_bytes) + + verified_contract_twin_query = + from( + smart_contract in SmartContract, + where: smart_contract.contract_code_md5 == ^contract_code_md5, + where: smart_contract.address_hash != ^target_address_hash, + select: smart_contract, + limit: 1 + ) + + verified_contract_twin_query + |> Repo.one(timeout: 10_000) + + _ -> + nil + end + end + @doc """ Finds metadata for verification of a contract from verified twins: contracts with the same bytecode which were verified previously, returns a single t:SmartContract.t/0 @@ -4216,24 +4240,8 @@ defmodule Explorer.Chain do def get_address_verified_twin_contract(%Explorer.Chain.Hash{} = address_hash) do with target_address <- Repo.get(Address, address_hash), - false <- is_nil(target_address), - %{contract_code: %Chain.Data{bytes: contract_code_bytes}} <- target_address do - target_address_hash = target_address.hash - - contract_code_md5 = Helper.contract_code_md5(contract_code_bytes) - - verified_contract_twin_query = - from( - smart_contract in SmartContract, - where: smart_contract.contract_code_md5 == ^contract_code_md5, - where: smart_contract.address_hash != ^target_address_hash, - select: smart_contract, - limit: 1 - ) - - verified_contract_twin = - verified_contract_twin_query - |> Repo.one(timeout: 10_000) + false <- is_nil(target_address) do + verified_contract_twin = get_verified_twin_contract(target_address) verified_contract_twin_additional_sources = get_contract_additional_sources(verified_contract_twin) diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index 3742f954c16f..0b18c8a3e43c 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -201,6 +201,7 @@ defmodule Explorer.Chain.SmartContract do * `bytecode_checked_at` - timestamp of the last check of contract's bytecode matching (DB and BlockChain) * `contract_code_md5` - md5(`t:Explorer.Chain.Address.t/0` `contract_code`) * `implementation_name` - name of the proxy implementation + * `settings` - raw compilation parameters * `autodetect_constructor_args` - field was added for storing user's choice * `is_yul` - field was added for storing user's choice """ @@ -222,6 +223,7 @@ defmodule Explorer.Chain.SmartContract do bytecode_checked_at: DateTime.t(), contract_code_md5: String.t(), implementation_name: String.t() | nil, + compiler_settings: map() | nil, autodetect_constructor_args: boolean | nil, is_yul: boolean | nil } @@ -244,6 +246,7 @@ defmodule Explorer.Chain.SmartContract do field(:bytecode_checked_at, :utc_datetime_usec, default: DateTime.add(DateTime.utc_now(), -86400, :second)) field(:contract_code_md5, :string) field(:implementation_name, :string) + field(:compiler_settings, :map) field(:autodetect_constructor_args, :boolean, virtual: true) field(:is_yul, :boolean, virtual: true) @@ -287,7 +290,8 @@ defmodule Explorer.Chain.SmartContract do :is_changed_bytecode, :bytecode_checked_at, :contract_code_md5, - :implementation_name + :implementation_name, + :compiler_settings ]) |> validate_required([ :name, diff --git a/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex b/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex index ccca2505bc88..34a2eab02dcf 100644 --- a/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex +++ b/apps/explorer/lib/explorer/smart_contract/rust_verifier_interface.ex @@ -48,7 +48,7 @@ defmodule Explorer.SmartContract.RustVerifierInterface do def http_post_request(url, body) do headers = [{"Content-Type", "application/json"}] - case HTTPoison.post(url, Jason.encode!(body), headers, recv_timeout: @post_timeout) do + case HTTPoison.post(url, Jason.encode!(normalize_creation_bytecode(body)), headers, recv_timeout: @post_timeout) do {:ok, %Response{body: body, status_code: 200}} -> proccess_verifier_response(body) @@ -125,6 +125,10 @@ defmodule Explorer.SmartContract.RustVerifierInterface do def proccess_verifier_response(other), do: {:error, other} + def normalize_creation_bytecode(%{"creation_bytecode" => ""} = map), do: Map.replace(map, "creation_bytecode", nil) + + def normalize_creation_bytecode(map), do: map + def multiple_files_verification_url, do: "#{base_api_url()}" <> "/solidity/verify/multiple-files" def vyper_multiple_files_verification_url, do: "#{base_api_url()}" <> "/vyper/verify/multiple-files" diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex index d98d8537b5c0..0ff49cb4806e 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex @@ -50,6 +50,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do |> Map.put("contract_source_code", contract_source_code) |> Map.put("external_libraries", contract_libraries) |> Map.put("name", contract_name) + |> cast_compiler_settings(false) publish_smart_contract(address_hash, prepared_params, Jason.decode!(abi_string || "null")) @@ -88,7 +89,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do "optimization_runs" => _, "sources" => _ } = result_params} -> - proccess_rust_verifier_response(result_params, address_hash) + proccess_rust_verifier_response(result_params, address_hash, true) {:ok, %{abi: abi, constructor_arguments: constructor_arguments}, additional_params} -> params_with_constructor_arguments = @@ -153,7 +154,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do "optimization_runs" => _, "sources" => sources } = result_params, - address_hash + address_hash, + is_standard_json? \\ false ) do secondary_sources = for {file, source} <- sources, @@ -169,10 +171,23 @@ defmodule Explorer.SmartContract.Solidity.Publisher do |> Map.put("name", contract_name) |> Map.put("file_path", file_name) |> Map.put("secondary_sources", secondary_sources) + |> cast_compiler_settings(is_standard_json?) publish_smart_contract(address_hash, prepared_params, Jason.decode!(abi_string)) end + def cast_compiler_settings(params, false), do: Map.put(params, "compiler_settings", nil) + + def cast_compiler_settings(params, true) do + case Jason.decode(params["compiler_settings"]) do + {:ok, map} -> + Map.put(params, "compiler_settings", map) + + _ -> + Map.put(params, "compiler_settings", nil) + end + end + def publish_smart_contract(address_hash, params, abi) do attrs = address_hash |> attributes(params, abi) @@ -217,6 +232,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do defp attributes(address_hash, params, abi \\ %{}) do constructor_arguments = params["constructor_arguments"] + compiler_settings = params["compiler_settings"] clean_constructor_arguments = if constructor_arguments != nil && constructor_arguments != "" do @@ -225,6 +241,13 @@ defmodule Explorer.SmartContract.Solidity.Publisher do nil end + clean_compiler_settings = + if compiler_settings in ["", nil, %{}] do + nil + else + compiler_settings + end + prepared_external_libraries = prepare_external_libraies(params["external_libraries"]) compiler_version = CompilerVersion.get_strict_compiler_version(:solc, params["compiler_version"]) @@ -246,7 +269,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do partially_verified: params["partially_verified"], is_vyper_contract: false, autodetect_constructor_args: params["autodetect_constructor_args"], - is_yul: params["is_yul"] || false + is_yul: params["is_yul"] || false, + compiler_settings: clean_compiler_settings } end diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex index 6e5c0e2919c9..eb849469ac58 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex @@ -205,6 +205,7 @@ defmodule Explorer.SmartContract.Solidity.Verifier do |> Map.put("file_path", file_path) |> Map.put("name", contract_name) |> Map.put("secondary_sources", secondary_sources) + |> Map.put("compiler_settings", map_json_input["settings"]) {:halt, {:ok, verified_data, additional_params}} diff --git a/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex b/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex index 7c34aca8e391..5ec6cee8ccd6 100644 --- a/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex +++ b/apps/explorer/lib/explorer/third_party_integrations/sourcify.ex @@ -312,6 +312,7 @@ defmodule Explorer.ThirdPartyIntegrations.Sourcify do |> Map.put("optimization_runs", Map.get(optimizer, "runs")) |> Map.put("external_libraries", Map.get(settings, "libraries")) |> Map.put("verified_via_sourcify", true) + |> Map.put("compiler_settings", settings) %{ "params_to_publish" => params, diff --git a/apps/explorer/priv/repo/migrations/20221120184715_add_json_compiler_settings.exs b/apps/explorer/priv/repo/migrations/20221120184715_add_json_compiler_settings.exs new file mode 100644 index 000000000000..e6f90d78648a --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20221120184715_add_json_compiler_settings.exs @@ -0,0 +1,9 @@ +defmodule Explorer.Repo.Migrations.AddJsonCompilerSettings do + use Ecto.Migration + + def change do + alter table(:smart_contracts) do + add(:compiler_settings, :jsonb, null: true) + end + end +end From 8fdc845e48afbfdef56b770dae6ad6647ef70076 Mon Sep 17 00:00:00 2001 From: nikitosing <32202610+nikitosing@users.noreply.github.com> Date: Mon, 28 Nov 2022 16:46:38 +0300 Subject: [PATCH 52/66] BS core API V2: /tokens, /main-page/indexing-status (#6515) * Complete /addresses/0x.. endpoint * Add token controller * Add tests for token controller * Fix credo --- .../lib/block_scout_web/api_router.ex | 8 + .../controllers/api/v2/address_controller.ex | 12 +- .../api/v2/main_page_controller.ex | 12 + .../controllers/api/v2/token_controller.ex | 63 +++++ .../controllers/tokens/token_controller.ex | 33 +-- .../views/api/v2/address_view.ex | 37 ++- .../views/api/v2/token_view.ex | 28 ++- .../api/v2/address_controller_test.exs | 22 +- .../api/v2/main_page_controller_test.exs | 12 + .../api/v2/token_controller_test.exs | 228 ++++++++++++++++++ apps/explorer/lib/explorer/chain.ex | 32 ++- .../chain/address/current_token_balance.ex | 2 +- 12 files changed, 440 insertions(+), 49 deletions(-) create mode 100644 apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex create mode 100644 apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs diff --git a/apps/block_scout_web/lib/block_scout_web/api_router.ex b/apps/block_scout_web/lib/block_scout_web/api_router.ex index 0d78f6f870c6..99ced87556f9 100644 --- a/apps/block_scout_web/lib/block_scout_web/api_router.ex +++ b/apps/block_scout_web/lib/block_scout_web/api_router.ex @@ -129,9 +129,17 @@ defmodule BlockScoutWeb.ApiRouter do get("/:address_hash/coin-balance-history-by-day", V2.AddressController, :coin_balance_history_by_day) end + scope "/tokens" do + get("/:address_hash", V2.TokenController, :token) + get("/:address_hash/counters", V2.TokenController, :counters) + get("/:address_hash/transfers", V2.TokenController, :transfers) + get("/:address_hash/holders", V2.TokenController, :holders) + end + scope "/main-page" do get("/blocks", V2.MainPageController, :blocks) get("/transactions", V2.MainPageController, :transactions) + get("/indexing-status", V2.MainPageController, :indexing_status) end scope "/stats" do diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex index 5ee15da7ec68..0e677fa567c6 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex @@ -57,10 +57,10 @@ defmodule BlockScoutWeb.API.V2.AddressController do address_gas_usage_from_db = address.gas_used || 0 json(conn, %{ - transaction_count: to_string(transactions_from_db), - token_transfer_count: to_string(token_transfers_from_db), + transactions_count: to_string(transactions_from_db), + token_transfers_count: to_string(token_transfers_from_db), gas_usage_count: to_string(address_gas_usage_from_db), - validation_count: to_string(validation_count) + validations_count: to_string(validation_count) }) end end @@ -119,15 +119,15 @@ defmodule BlockScoutWeb.API.V2.AddressController do options ) - {transactions, next_page} = split_list_by_page(results_plus_one) + {token_transfers, next_page} = split_list_by_page(results_plus_one) next_page_params = - next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params() + next_page |> next_page_params(token_transfers, params) |> delete_parameters_from_next_page_params() conn |> put_status(200) |> put_view(TransactionView) - |> render(:token_transfers, %{token_transfers: transactions, next_page_params: next_page_params}) + |> render(:token_transfers, %{token_transfers: token_transfers, next_page_params: next_page_params}) end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex index 0d49281f7f84..1851cd9a3ea9 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/main_page_controller.ex @@ -37,4 +37,16 @@ defmodule BlockScoutWeb.API.V2.MainPageController do |> put_view(TransactionView) |> render(:transactions, %{transactions: recent_transactions}) end + + def indexing_status(conn, _params) do + indexed_ratio_blocks = Chain.indexed_ratio_blocks() + finished_indexing_blocks = Chain.finished_blocks_indexing?(indexed_ratio_blocks) + + json(conn, %{ + finished_indexing_blocks: finished_indexing_blocks, + finished_indexing: Chain.finished_indexing?(indexed_ratio_blocks), + indexed_blocks_ratio: indexed_ratio_blocks, + indexed_inernal_transactions_ratio: if(finished_indexing_blocks, do: Chain.indexed_ratio_internal_transactions()) + }) + end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex new file mode 100644 index 000000000000..79998a4aaa82 --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex @@ -0,0 +1,63 @@ +defmodule BlockScoutWeb.API.V2.TokenController do + use BlockScoutWeb, :controller + + alias BlockScoutWeb.API.V2.TransactionView + alias Explorer.Chain + + import BlockScoutWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3] + import BlockScoutWeb.PagingHelper, only: [delete_parameters_from_next_page_params: 1] + + action_fallback(BlockScoutWeb.API.V2.FallbackController) + + def token(conn, %{"address_hash" => address_hash_string}) do + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, + {:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash)} do + conn + |> put_status(200) + |> render(:token, %{token: token}) + end + end + + def counters(conn, %{"address_hash" => address_hash_string}) do + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, + {:not_found, {:ok, _}} <- {:not_found, Chain.token_from_address_hash(address_hash)} do + {transfer_count, token_holder_count} = Chain.fetch_token_counters(address_hash, 30_000) + + json(conn, %{transfers_count: to_string(transfer_count), token_holders_count: to_string(token_holder_count)}) + end + end + + def transfers(conn, %{"address_hash" => address_hash_string} = params) do + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)} do + results_plus_one = Chain.fetch_token_transfers_from_token_hash(address_hash, paging_options(params)) + + {token_transfers, next_page} = split_list_by_page(results_plus_one) + + next_page_params = + next_page |> next_page_params(token_transfers, params) |> delete_parameters_from_next_page_params() + + conn + |> put_status(200) + |> put_view(TransactionView) + |> render(:token_transfers, %{token_transfers: token_transfers, next_page_params: next_page_params}) + end + end + + def holders(conn, %{"address_hash" => address_hash_string} = params) do + from_api = true + + with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, + {:not_found, {:ok, token}, _} <- + {:not_found, Chain.token_from_address_hash(address_hash), :empty_items_with_next_page_params} do + results_plus_one = Chain.fetch_token_holders_from_token_hash(address_hash, from_api, paging_options(params)) + {token_balances, next_page} = split_list_by_page(results_plus_one) + + next_page_params = + next_page |> next_page_params(token_balances, params) |> delete_parameters_from_next_page_params() + + conn + |> put_status(200) + |> render(:token_balances, %{token_balances: token_balances, next_page_params: next_page_params, token: token}) + end + end +end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/token_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/token_controller.ex index 6a1ea07b1730..73739141e7dd 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/token_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/token_controller.ex @@ -5,7 +5,6 @@ defmodule BlockScoutWeb.Tokens.TokenController do alias BlockScoutWeb.AccessHelpers alias Explorer.Chain - alias Explorer.Counters.{TokenHoldersCounter, TokenTransfersCounter} def show(conn, %{"id" => address_hash_string}) do redirect(conn, to: AccessHelpers.get_path(conn, :token_transfer_path, :index, address_hash_string)) @@ -14,7 +13,7 @@ defmodule BlockScoutWeb.Tokens.TokenController do def token_counters(conn, %{"id" => address_hash_string}) do case Chain.string_to_address_hash(address_hash_string) do {:ok, address_hash} -> - {transfer_count, token_holder_count} = fetch_token_counters(address_hash, 30_000) + {transfer_count, token_holder_count} = Chain.fetch_token_counters(address_hash, 30_000) json(conn, %{transfer_count: transfer_count, token_holder_count: token_holder_count}) @@ -22,34 +21,4 @@ defmodule BlockScoutWeb.Tokens.TokenController do not_found(conn) end end - - defp fetch_token_counters(address_hash, timeout) do - total_token_transfers_task = - Task.async(fn -> - TokenTransfersCounter.fetch(address_hash) - end) - - total_token_holders_task = - Task.async(fn -> - TokenHoldersCounter.fetch(address_hash) - end) - - [total_token_transfers_task, total_token_holders_task] - |> Task.yield_many(timeout) - |> Enum.map(fn {_task, res} -> - case res do - {:ok, result} -> - result - - {:exit, reason} -> - Logger.warn("Query fetching token counters terminated: #{inspect(reason)}") - 0 - - nil -> - Logger.warn("Query fetching token counters timed out.") - 0 - end - end) - |> List.to_tuple() - end end diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex index 54511abc0027..7cea8b97ec27 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex @@ -1,8 +1,12 @@ defmodule BlockScoutWeb.API.V2.AddressView do use BlockScoutWeb, :view + alias BlockScoutWeb.AddressView alias BlockScoutWeb.API.V2.{ApiView, Helper, TokenView} alias BlockScoutWeb.API.V2.Helper + alias Explorer.{Chain, Market} + alias Explorer.Chain.Address + alias Explorer.ExchangeRates.Token def render("message.json", assigns) do ApiView.render("message.json", assigns) @@ -29,7 +33,38 @@ defmodule BlockScoutWeb.API.V2.AddressView do end def prepare_address(address, conn \\ nil) do - Helper.address_with_info(conn, address, address.hash) + base_info = Helper.address_with_info(conn, address, address.hash) + is_proxy = AddressView.smart_contract_is_proxy?(address) + + {implementation_address, implementation_name} = + with true <- is_proxy, + {address, name} <- Chain.get_implementation_address_hash(address.hash, address.smart_contract.abi), + false <- is_nil(address), + {:ok, address_hash} <- Chain.string_to_address_hash(address), + checksummed_address <- Address.checksum(address_hash) do + {checksummed_address, name} + else + _ -> + {nil, nil} + end + + balance = address.fetched_coin_balance && address.fetched_coin_balance.value + exchange_rate = (Market.get_exchange_rate(Explorer.coin()) || Token.null()).usd_value + + creator_hash = AddressView.from_address_hash(address) + creation_tx = creator_hash && AddressView.transaction_hash(address) + token = address.token && TokenView.render("token.json", %{token: Market.add_price(address.token)}) + + Map.merge(base_info, %{ + "creator_address_hash" => creator_hash && Address.checksum(creator_hash), + "creation_tx_hash" => creation_tx, + "token" => token, + "coin_balance" => balance, + "exchange_rate" => exchange_rate, + "implementation_name" => implementation_name, + "implementation_address" => implementation_address, + "block_number_balance_updated_at" => address.fetched_coin_balance_block_number + }) end def prepare_token_balance({token_balance, token}) do diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex index 1806ec9d3371..66ae64783ffe 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex @@ -1,4 +1,5 @@ defmodule BlockScoutWeb.API.V2.TokenView do + alias BlockScoutWeb.API.V2.Helper alias Explorer.Chain.Address def render("token.json", %{token: token}) do @@ -9,7 +10,32 @@ defmodule BlockScoutWeb.API.V2.TokenView do "decimals" => token.decimals, "type" => token.type, "holders" => token.holder_count && to_string(token.holder_count), - "exchange_rate" => token.usd_value && to_string(token.usd_value) + "exchange_rate" => exchange_rate(token), + "total_supply" => token.total_supply + } + end + + def render("token_balances.json", %{ + token_balances: token_balances, + next_page_params: next_page_params, + conn: conn, + token: token + }) do + %{ + "items" => Enum.map(token_balances, &prepare_token_balance(&1, conn, token)), + "next_page_params" => next_page_params + } + end + + def exchange_rate(%{usd_value: usd_value}) when not is_nil(usd_value), do: to_string(usd_value) + def exchange_rate(_), do: nil + + def prepare_token_balance(token_balance, conn, token) do + %{ + "address" => Helper.address_with_info(conn, token_balance.address, token_balance.address_hash), + "value" => token_balance.value, + "token_id" => token_balance.token_id, + "token" => render("token.json", %{token: token}) } end end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs index 7542666ecaad..33fbe54aee77 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs @@ -42,7 +42,15 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do "name" => nil, "private_tags" => [], "public_tags" => [], - "watchlist_names" => [] + "watchlist_names" => [], + "creator_address_hash" => nil, + "creation_tx_hash" => nil, + "token" => nil, + "coin_balance" => nil, + "exchange_rate" => nil, + "implementation_name" => nil, + "implementation_address" => nil, + "block_number_balance_updated_at" => nil } request = get(conn, "/api/v2/addresses/#{Address.checksum(address.hash)}") @@ -74,10 +82,10 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do request = get(conn, "/api/v2/addresses/#{address.hash}/counters") assert %{ - "transaction_count" => "0", - "token_transfer_count" => "0", + "transactions_count" => "0", + "token_transfers_count" => "0", "gas_usage_count" => "0", - "validation_count" => "0" + "validations_count" => "0" } = json_response(request, 200) end @@ -113,10 +121,10 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do gas_used = to_string(tx_from.gas_used) assert %{ - "transaction_count" => "2", - "token_transfer_count" => "2", + "transactions_count" => "2", + "token_transfers_count" => "2", "gas_usage_count" => ^gas_used, - "validation_count" => "1" + "validations_count" => "1" } = json_response(request, 200) end end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs index 75c5e2183926..b1e27673df8c 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/main_page_controller_test.exs @@ -50,6 +50,18 @@ defmodule BlockScoutWeb.API.V2.MainPageControllerTest do end end + describe "/main-page/indexing-status" do + test "get indexing status", %{conn: conn} do + request = get(conn, "/api/v2/main-page/indexing-status") + assert request = json_response(request, 200) + + assert Map.has_key?(request, "finished_indexing_blocks") + assert Map.has_key?(request, "finished_indexing") + assert Map.has_key?(request, "indexed_blocks_ratio") + assert Map.has_key?(request, "indexed_inernal_transactions_ratio") + end + end + defp compare_item(%Block{} = block, json) do assert to_string(block.hash) == json["hash"] assert block.number == json["height"] diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs new file mode 100644 index 000000000000..a0751c6bfee2 --- /dev/null +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs @@ -0,0 +1,228 @@ +defmodule BlockScoutWeb.API.V2.TokenControllerTest do + use BlockScoutWeb.ConnCase + + alias Explorer.{Chain, Repo} + + alias Explorer.Chain.{Address, Token, TokenTransfer} + + alias Explorer.Chain.Address.CurrentTokenBalance + + describe "/tokens/{address_hash}" do + test "get 404 on non existing address", %{conn: conn} do + token = build(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}") + + assert %{"message" => "Not found"} = json_response(request, 404) + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/tokens/0x") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get token", %{conn: conn} do + token = insert(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}") + + assert response = json_response(request, 200) + + compare_item(token, response) + end + end + + describe "/tokens/{address_hash}/counters" do + test "get 404 on non existing address", %{conn: conn} do + token = build(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/counters") + + assert %{"message" => "Not found"} = json_response(request, 404) + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/tokens/0x/counters") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get counters", %{conn: conn} do + token = insert(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/counters") + + assert response = json_response(request, 200) + + assert response["transfers_count"] == "0" + assert response["token_holders_count"] == "0" + end + + test "get not zero counters", %{conn: conn} do + contract_token_address = insert(:contract_address) + token = insert(:token, contract_address: contract_token_address) + + transaction = + :transaction + |> insert(to_address: contract_token_address) + |> with_block() + + insert_list( + 3, + :token_transfer, + transaction: transaction, + token_contract_address: contract_token_address + ) + + second_page_token_balances = + 1..5 + |> Enum.map( + &insert( + :address_current_token_balance, + token_contract_address_hash: token.contract_address_hash, + value: &1 + 1000 + ) + ) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/counters") + + assert response = json_response(request, 200) + + assert response["transfers_count"] == "3" + assert response["token_holders_count"] == "5" + end + end + + describe "/tokens/{address_hash}/transfers" do + test "get 200 on non existing address", %{conn: conn} do + token = build(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/transfers") + + assert %{"items" => [], "next_page_params" => nil} = json_response(request, 200) + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/tokens/0x/transfers") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get empty list", %{conn: conn} do + token = insert(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/transfers") + + assert %{"items" => [], "next_page_params" => nil} = json_response(request, 200) + end + + test "check pagination", %{conn: conn} do + token = insert(:token) + + token_tranfers = + for _ <- 0..50 do + tx = insert(:transaction) |> with_block() + + insert(:token_transfer, + transaction: tx, + block: tx.block, + block_number: tx.block_number, + token_contract_address: token.contract_address + ) + end + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/transfers") + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/tokens/#{token.contract_address.hash}/transfers", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, token_tranfers) + end + end + + describe "/tokens/{address_hash}/holders" do + test "get 200 on non existing address", %{conn: conn} do + token = build(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/holders") + + assert %{"items" => [], "next_page_params" => nil} = json_response(request, 200) + end + + test "get 422 on invalid address", %{conn: conn} do + request = get(conn, "/api/v2/tokens/0x/holders") + + assert %{"message" => "Invalid parameter(s)"} = json_response(request, 422) + end + + test "get empty list", %{conn: conn} do + token = insert(:token) + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/holders") + + assert %{"items" => [], "next_page_params" => nil} = json_response(request, 200) + end + + test "check pagination", %{conn: conn} do + token = insert(:token) + + token_balances = + for i <- 0..50 do + insert( + :address_current_token_balance, + token_contract_address_hash: token.contract_address_hash, + value: i + 1000 + ) + end + + request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/holders") + assert response = json_response(request, 200) + + request_2nd_page = + get(conn, "/api/v2/tokens/#{token.contract_address.hash}/holders", response["next_page_params"]) + + assert response_2nd_page = json_response(request_2nd_page, 200) + + check_paginated_response(response, response_2nd_page, token_balances) + end + end + + def compare_item(%Token{} = token, json) do + assert Address.checksum(token.contract_address.hash) == json["address"] + assert token.symbol == json["symbol"] + assert token.name == json["name"] + assert to_string(token.decimals) == json["decimals"] + assert token.type == json["type"] + assert token.holder_count == json["holders"] + assert to_string(token.total_supply) == json["total_supply"] + assert Map.has_key?(json, "exchange_rate") + end + + def compare_item(%TokenTransfer{} = token_transfer, json) do + assert Address.checksum(token_transfer.from_address_hash) == json["from"]["hash"] + assert Address.checksum(token_transfer.to_address_hash) == json["to"]["hash"] + assert to_string(token_transfer.transaction_hash) == json["tx_hash"] + end + + def compare_item(%CurrentTokenBalance{} = ctb, json) do + assert Address.checksum(ctb.address_hash) == json["address"]["hash"] + assert ctb.token_id == json["token_id"] + assert to_string(ctb.value) == json["value"] + compare_item(Repo.preload(ctb, [{:token, :contract_address}]).token, json["token"]) + end + + defp check_paginated_response(first_page_resp, second_page_resp, list) do + assert Enum.count(first_page_resp["items"]) == 50 + assert first_page_resp["next_page_params"] != nil + compare_item(Enum.at(list, 50), Enum.at(first_page_resp["items"], 0)) + compare_item(Enum.at(list, 1), Enum.at(first_page_resp["items"], 49)) + + assert Enum.count(second_page_resp["items"]) == 1 + assert second_page_resp["next_page_params"] == nil + compare_item(Enum.at(list, 0), Enum.at(second_page_resp["items"], 0)) + end +end diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index bf4cff852cad..ef481b723220 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -36,7 +36,7 @@ defmodule Explorer.Chain do alias EthereumJSONRPC.Contract alias EthereumJSONRPC.Transaction, as: EthereumJSONRPCTransaction - alias Explorer.Counters.LastFetchedCounter + alias Explorer.Counters.{LastFetchedCounter, TokenHoldersCounter, TokenTransfersCounter} alias Explorer.Chain @@ -6638,4 +6638,34 @@ defmodule Explorer.Chain do def gas_usage_count(address) do AddressTransactionsGasUsageCounter.fetch(address) end + + def fetch_token_counters(address_hash, timeout) do + total_token_transfers_task = + Task.async(fn -> + TokenTransfersCounter.fetch(address_hash) + end) + + total_token_holders_task = + Task.async(fn -> + TokenHoldersCounter.fetch(address_hash) + end) + + [total_token_transfers_task, total_token_holders_task] + |> Task.yield_many(timeout) + |> Enum.map(fn {_task, res} -> + case res do + {:ok, result} -> + result + + {:exit, reason} -> + Logger.warn("Query fetching token counters terminated: #{inspect(reason)}") + 0 + + nil -> + Logger.warn("Query fetching token counters timed out.") + 0 + end + end) + |> List.to_tuple() + end end diff --git a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex index 4cf3fbd813d0..93174cb70c5f 100644 --- a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex +++ b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex @@ -23,7 +23,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do * `token_contract_address_hash` - The contract address hash foreign key. * `block_number` - The block's number that the transfer took place. * `value` - The value that's represents the balance. - * `token_id` - The token_id of the transferred token (applicable for ERC-1155 and ERC-721 tokens) + * `token_id` - The token_id of the transferred token (applicable for ERC-1155) * `token_type` - The type of the token """ @type t :: %__MODULE__{ From 708a6b00362689aab50db8f0cd996c2de66013ed Mon Sep 17 00:00:00 2001 From: nikitosing <32202610+nikitosing@users.noreply.github.com> Date: Mon, 28 Nov 2022 19:08:50 +0300 Subject: [PATCH 53/66] Improve working with contracts implementations (#5561) * Fix error on invalid response from node while fetching implementation address; Improve storing the implementation name * Add time out on implementation fetching and storing implementation info in DB * Add tests for contracts implementation fetching; Fixes for SmartContract module * Fixes after rebase * Refactor --- CHANGELOG.md | 1 + .../controllers/smart_contract_controller.ex | 5 +- .../templates/address/overview.html.eex | 35 +- .../lib/block_scout_web/views/address_view.ex | 4 +- .../views/tokens/overview_view.ex | 4 +- apps/block_scout_web/priv/gettext/default.pot | 98 ++--- .../priv/gettext/en/LC_MESSAGES/default.po | 98 ++--- .../lib/ethereum_jsonrpc/http.ex | 14 +- .../ethereum_jsonrpc/request_coordinator.ex | 2 +- apps/explorer/config/test.exs | 6 +- apps/explorer/lib/explorer/chain.ex | 264 ++---------- apps/explorer/lib/explorer/chain/log.ex | 4 +- .../lib/explorer/chain/smart_contract.ex | 384 +++++++++++++++++- .../lib/explorer/chain/transaction.ex | 13 +- .../lib/explorer/etherscan/contracts.ex | 6 +- .../lib/explorer/smart_contract/reader.ex | 9 +- ...220527131249_add_implementation_fields.exs | 10 + .../explorer/chain/smart_contract_test.exs | 237 +++++++++++ apps/explorer/test/explorer/chain_test.exs | 50 ++- config/runtime.exs | 6 +- 20 files changed, 850 insertions(+), 400 deletions(-) create mode 100644 apps/explorer/priv/repo/migrations/20220527131249_add_implementation_fields.exs create mode 100644 apps/explorer/test/explorer/chain/smart_contract_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b864ff6b0a9..501d655a9369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- [#5561](https://github.com/blockscout/blockscout/pull/5561) - Improve working with contracts implementations - [#6401](https://github.com/blockscout/blockscout/pull/6401) - Add Sol2Uml contract visualization - [#6481](https://github.com/blockscout/blockscout/pull/6481) - Smart contract verification improvements - [#6444](https://github.com/blockscout/blockscout/pull/6444) - Add support for yul verification via rust microservice diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex index ab3819c4c827..7d9d0964a9f9 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex @@ -3,6 +3,7 @@ defmodule BlockScoutWeb.SmartContractController do alias BlockScoutWeb.AddressView alias Explorer.Chain + alias Explorer.Chain.SmartContract alias Explorer.SmartContract.{Reader, Writer} import Explorer.SmartContract.Solidity.Verifier, only: [parse_boolean: 1] @@ -24,8 +25,8 @@ defmodule BlockScoutWeb.SmartContractController do {:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do implementation_address_hash_string = if contract_type == "proxy" do - address.hash - |> Chain.get_implementation_address_hash(address.smart_contract.abi) + address.smart_contract + |> SmartContract.get_implementation_address_hash() |> Tuple.to_list() |> List.first() || @burn_address else diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex index 34059b2ed9dd..9a8abc9dd7b2 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex @@ -124,24 +124,23 @@ <% end %> <%= if @is_proxy do %> - <% {implementation_address, name} = Chain.get_implementation_address_hash(@address.hash, @address.smart_contract.abi) || "0x0000000000000000000000000000000000000000" %> - <%= if implementation_address do %> -
-
- <%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html", - text: gettext("Implementation address of the proxy contract.") %> - <%= gettext("Implementation") %> -
-
- <%= link( - (if name, do: name <> " | " <> implementation_address, else: implementation_address), - to: address_path(@conn, :show, implementation_address), - class: "contract-address" - ) - %> -
-
- <% end %> + <% {implementation_address_, name} = SmartContract.get_implementation_address_hash(@address.smart_contract) %> + <% implementation_address = implementation_address_ || "0x0000000000000000000000000000000000000000" %> +
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html", + text: gettext("Implementation address of the proxy contract.") %> + <%= gettext("Implementation") %> +
+
+ <%= link( + (if name, do: name <> " | " <> implementation_address, else: implementation_address), + to: address_path(@conn, :show, implementation_address), + class: "contract-address" + ) + %> +
+
<% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex index b1d184959862..ac75f3e0ddbe 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex @@ -261,8 +261,8 @@ defmodule BlockScoutWeb.AddressView do def is_read_function?(function), do: Helper.queriable_method?(function) || Helper.read_with_wallet_method?(function) - def smart_contract_is_proxy?(%Address{smart_contract: %SmartContract{}} = address) do - Chain.proxy_contract?(address.hash, address.smart_contract.abi) + def smart_contract_is_proxy?(%Address{smart_contract: %SmartContract{} = smart_contract}) do + SmartContract.proxy_contract?(smart_contract) end def smart_contract_is_proxy?(%Address{smart_contract: nil}), do: false diff --git a/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex b/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex index 473c2df3e2e1..4fc1c6d28ef4 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/tokens/overview_view.ex @@ -53,8 +53,8 @@ defmodule BlockScoutWeb.Tokens.OverviewView do def smart_contract_with_read_only_functions?(%Token{contract_address: %Address{smart_contract: nil}}), do: false - def smart_contract_is_proxy?(%Token{contract_address: %Address{smart_contract: %SmartContract{}} = address}) do - Chain.proxy_contract?(address.hash, address.smart_contract.abi) + def smart_contract_is_proxy?(%Token{contract_address: %Address{smart_contract: %SmartContract{} = smart_contract}}) do + SmartContract.proxy_contract?(smart_contract) end def smart_contract_is_proxy?(%Token{contract_address: %Address{smart_contract: nil}}), do: false diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index b1258df630b5..153f4521d2c3 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -256,7 +256,7 @@ msgstr "" msgid "Address Tags" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:150 +#: lib/block_scout_web/templates/address/overview.html.eex:149 #, elixir-autogen, elixir-format msgid "Address balance in" msgstr "" @@ -304,7 +304,7 @@ msgstr "" msgid "All metadata displayed below is from that contract. In order to verify current contract, click" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:175 +#: lib/block_scout_web/templates/address/overview.html.eex:174 #, elixir-autogen, elixir-format msgid "All tokens in the account and total value." msgstr "" @@ -371,7 +371,7 @@ msgid "Back to Watch list (Cancel)" msgstr "" #: lib/block_scout_web/templates/account/watchlist/show.html.eex:24 -#: lib/block_scout_web/templates/address/overview.html.eex:151 +#: lib/block_scout_web/templates/address/overview.html.eex:150 #: lib/block_scout_web/templates/address_token/overview.html.eex:51 #: lib/block_scout_web/templates/verified_contracts/index.html.eex:57 #, elixir-autogen, elixir-format @@ -463,7 +463,7 @@ msgstr "" msgid "Block number containing the transaction." msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:258 +#: lib/block_scout_web/templates/address/overview.html.eex:257 #, elixir-autogen, elixir-format msgid "Block number in which the address was updated." msgstr "" @@ -491,7 +491,7 @@ msgid "Blocks Indexed" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:48 -#: lib/block_scout_web/templates/address/overview.html.eex:276 +#: lib/block_scout_web/templates/address/overview.html.eex:275 #: lib/block_scout_web/templates/address_validation/index.html.eex:11 #: lib/block_scout_web/views/address_view.ex:381 #, elixir-autogen, elixir-format @@ -620,6 +620,11 @@ msgstr "" msgid "Compiler" msgstr "" +#: lib/block_scout_web/templates/address_contract/index.html.eex:137 +#, elixir-autogen, elixir-format +msgid "Compiler Settings" +msgstr "" + #: lib/block_scout_web/templates/address_contract/index.html.eex:66 #, elixir-autogen, elixir-format msgid "Compiler version" @@ -805,6 +810,11 @@ msgstr "" msgid "Copy Address" msgstr "" +#: lib/block_scout_web/templates/address_contract/index.html.eex:139 +#, elixir-autogen, elixir-format +msgid "Copy Compiler Settings" +msgstr "" + #: lib/block_scout_web/templates/account/custom_abi/row.html.eex:6 #: lib/block_scout_web/templates/account/custom_abi/row.html.eex:6 #, elixir-autogen, elixir-format @@ -1281,7 +1291,7 @@ msgstr "" msgid "Fast" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:248 +#: lib/block_scout_web/templates/address/overview.html.eex:247 #, elixir-autogen, elixir-format msgid "Fetching gas used..." msgstr "" @@ -1296,14 +1306,14 @@ msgstr "" msgid "Fetching tokens..." msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:195 -#: lib/block_scout_web/templates/address/overview.html.eex:203 +#: lib/block_scout_web/templates/address/overview.html.eex:194 +#: lib/block_scout_web/templates/address/overview.html.eex:202 #, elixir-autogen, elixir-format msgid "Fetching transactions..." msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:222 -#: lib/block_scout_web/templates/address/overview.html.eex:230 +#: lib/block_scout_web/templates/address/overview.html.eex:221 +#: lib/block_scout_web/templates/address/overview.html.eex:229 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:123 #, elixir-autogen, elixir-format msgid "Fetching transfers..." @@ -1362,7 +1372,7 @@ msgstr "" msgid "Gas Price" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:241 +#: lib/block_scout_web/templates/address/overview.html.eex:240 #: lib/block_scout_web/templates/block/_tile.html.eex:73 #: lib/block_scout_web/templates/block/overview.html.eex:178 #, elixir-autogen, elixir-format @@ -1380,7 +1390,7 @@ msgstr "" msgid "Gas tracker" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:240 +#: lib/block_scout_web/templates/address/overview.html.eex:239 #, elixir-autogen, elixir-format msgid "Gas used by the address." msgstr "" @@ -1474,6 +1484,11 @@ msgstr "" msgid "Implementation address of the proxy contract." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Include nightly builds" +msgstr "" + #: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:30 #: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:43 #: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:56 @@ -1549,7 +1564,7 @@ msgstr "" msgid "Last 24h" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:259 +#: lib/block_scout_web/templates/address/overview.html.eex:258 #, elixir-autogen, elixir-format msgid "Last Balance Update" msgstr "" @@ -1874,7 +1889,7 @@ msgstr "" msgid "Number of accounts holding the token" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:275 +#: lib/block_scout_web/templates/address/overview.html.eex:274 #, elixir-autogen, elixir-format msgid "Number of blocks validated by this validator." msgstr "" @@ -1884,7 +1899,7 @@ msgstr "" msgid "Number of digits that come after the decimal place when displaying token value" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:186 +#: lib/block_scout_web/templates/address/overview.html.eex:185 #, elixir-autogen, elixir-format msgid "Number of transactions related to this address." msgstr "" @@ -1894,7 +1909,7 @@ msgstr "" msgid "Number of transfers for the token" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:213 +#: lib/block_scout_web/templates/address/overview.html.eex:212 #, elixir-autogen, elixir-format msgid "Number of transfers to/from this address." msgstr "" @@ -2240,6 +2255,11 @@ msgstr "" msgid "Select Yes if you want to vefify Yul contract." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select yes if you want to show nightly builds." +msgstr "" + #: lib/block_scout_web/views/internal_transaction_view.ex:27 #, elixir-autogen, elixir-format msgid "Self-Destruct" @@ -2776,7 +2796,7 @@ msgid "Token type" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:21 -#: lib/block_scout_web/templates/address/overview.html.eex:176 +#: lib/block_scout_web/templates/address/overview.html.eex:175 #: lib/block_scout_web/templates/address_token/overview.html.eex:58 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13 #: lib/block_scout_web/templates/layout/_topnav.html.eex:78 @@ -2935,9 +2955,9 @@ msgid "Transaction type, introduced in EIP-2718." msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:7 -#: lib/block_scout_web/templates/address/overview.html.eex:187 -#: lib/block_scout_web/templates/address/overview.html.eex:193 -#: lib/block_scout_web/templates/address/overview.html.eex:201 +#: lib/block_scout_web/templates/address/overview.html.eex:186 +#: lib/block_scout_web/templates/address/overview.html.eex:192 +#: lib/block_scout_web/templates/address/overview.html.eex:200 #: lib/block_scout_web/templates/address_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block/overview.html.eex:80 #: lib/block_scout_web/templates/block_transaction/index.html.eex:10 @@ -2958,9 +2978,9 @@ msgstr "" msgid "Transactions sent" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:214 -#: lib/block_scout_web/templates/address/overview.html.eex:220 -#: lib/block_scout_web/templates/address/overview.html.eex:228 +#: lib/block_scout_web/templates/address/overview.html.eex:213 +#: lib/block_scout_web/templates/address/overview.html.eex:219 +#: lib/block_scout_web/templates/address/overview.html.eex:227 #: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:50 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:119 #, elixir-autogen, elixir-format @@ -2973,6 +2993,11 @@ msgstr "" msgid "Try it out" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Try to fetch constructor arguments automatically" +msgstr "" + #: lib/block_scout_web/templates/layout/_footer.html.eex:27 #, elixir-autogen, elixir-format msgid "Twitter" @@ -3383,7 +3408,7 @@ msgstr "" msgid "custom RPC" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:150 +#: lib/block_scout_web/templates/address/overview.html.eex:149 #, elixir-autogen, elixir-format msgid "doesn't include ERC20, ERC721, ERC1155 tokens)." msgstr "" @@ -3463,28 +3488,3 @@ msgstr "" #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:3 -#, elixir-autogen, elixir-format -msgid "Include nightly builds" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19 -#, elixir-autogen, elixir-format -msgid "Select yes if you want to show nightly builds." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:3 -#, elixir-autogen, elixir-format -msgid "Try to fetch constructor arguments automatically" -msgstr "" - -#: lib/block_scout_web/templates/address_contract/index.html.eex:137 -#, elixir-autogen, elixir-format -msgid "Compiler Settings" -msgstr "" - -#: lib/block_scout_web/templates/address_contract/index.html.eex:139 -#, elixir-autogen, elixir-format -msgid "Copy Compiler Settings" -msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index b5d53aba9021..153f4521d2c3 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -256,7 +256,7 @@ msgstr "" msgid "Address Tags" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:150 +#: lib/block_scout_web/templates/address/overview.html.eex:149 #, elixir-autogen, elixir-format msgid "Address balance in" msgstr "" @@ -304,7 +304,7 @@ msgstr "" msgid "All metadata displayed below is from that contract. In order to verify current contract, click" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:175 +#: lib/block_scout_web/templates/address/overview.html.eex:174 #, elixir-autogen, elixir-format msgid "All tokens in the account and total value." msgstr "" @@ -371,7 +371,7 @@ msgid "Back to Watch list (Cancel)" msgstr "" #: lib/block_scout_web/templates/account/watchlist/show.html.eex:24 -#: lib/block_scout_web/templates/address/overview.html.eex:151 +#: lib/block_scout_web/templates/address/overview.html.eex:150 #: lib/block_scout_web/templates/address_token/overview.html.eex:51 #: lib/block_scout_web/templates/verified_contracts/index.html.eex:57 #, elixir-autogen, elixir-format @@ -463,7 +463,7 @@ msgstr "" msgid "Block number containing the transaction." msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:258 +#: lib/block_scout_web/templates/address/overview.html.eex:257 #, elixir-autogen, elixir-format msgid "Block number in which the address was updated." msgstr "" @@ -491,7 +491,7 @@ msgid "Blocks Indexed" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:48 -#: lib/block_scout_web/templates/address/overview.html.eex:276 +#: lib/block_scout_web/templates/address/overview.html.eex:275 #: lib/block_scout_web/templates/address_validation/index.html.eex:11 #: lib/block_scout_web/views/address_view.ex:381 #, elixir-autogen, elixir-format @@ -620,6 +620,11 @@ msgstr "" msgid "Compiler" msgstr "" +#: lib/block_scout_web/templates/address_contract/index.html.eex:137 +#, elixir-autogen, elixir-format +msgid "Compiler Settings" +msgstr "" + #: lib/block_scout_web/templates/address_contract/index.html.eex:66 #, elixir-autogen, elixir-format msgid "Compiler version" @@ -805,6 +810,11 @@ msgstr "" msgid "Copy Address" msgstr "" +#: lib/block_scout_web/templates/address_contract/index.html.eex:139 +#, elixir-autogen, elixir-format +msgid "Copy Compiler Settings" +msgstr "" + #: lib/block_scout_web/templates/account/custom_abi/row.html.eex:6 #: lib/block_scout_web/templates/account/custom_abi/row.html.eex:6 #, elixir-autogen, elixir-format @@ -1281,7 +1291,7 @@ msgstr "" msgid "Fast" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:248 +#: lib/block_scout_web/templates/address/overview.html.eex:247 #, elixir-autogen, elixir-format msgid "Fetching gas used..." msgstr "" @@ -1296,14 +1306,14 @@ msgstr "" msgid "Fetching tokens..." msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:195 -#: lib/block_scout_web/templates/address/overview.html.eex:203 +#: lib/block_scout_web/templates/address/overview.html.eex:194 +#: lib/block_scout_web/templates/address/overview.html.eex:202 #, elixir-autogen, elixir-format msgid "Fetching transactions..." msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:222 -#: lib/block_scout_web/templates/address/overview.html.eex:230 +#: lib/block_scout_web/templates/address/overview.html.eex:221 +#: lib/block_scout_web/templates/address/overview.html.eex:229 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:123 #, elixir-autogen, elixir-format msgid "Fetching transfers..." @@ -1362,7 +1372,7 @@ msgstr "" msgid "Gas Price" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:241 +#: lib/block_scout_web/templates/address/overview.html.eex:240 #: lib/block_scout_web/templates/block/_tile.html.eex:73 #: lib/block_scout_web/templates/block/overview.html.eex:178 #, elixir-autogen, elixir-format @@ -1380,7 +1390,7 @@ msgstr "" msgid "Gas tracker" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:240 +#: lib/block_scout_web/templates/address/overview.html.eex:239 #, elixir-autogen, elixir-format msgid "Gas used by the address." msgstr "" @@ -1474,6 +1484,11 @@ msgstr "" msgid "Implementation address of the proxy contract." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Include nightly builds" +msgstr "" + #: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:30 #: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:43 #: lib/block_scout_web/templates/account/watchlist_address/form.html.eex:56 @@ -1549,7 +1564,7 @@ msgstr "" msgid "Last 24h" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:259 +#: lib/block_scout_web/templates/address/overview.html.eex:258 #, elixir-autogen, elixir-format msgid "Last Balance Update" msgstr "" @@ -1874,7 +1889,7 @@ msgstr "" msgid "Number of accounts holding the token" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:275 +#: lib/block_scout_web/templates/address/overview.html.eex:274 #, elixir-autogen, elixir-format msgid "Number of blocks validated by this validator." msgstr "" @@ -1884,7 +1899,7 @@ msgstr "" msgid "Number of digits that come after the decimal place when displaying token value" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:186 +#: lib/block_scout_web/templates/address/overview.html.eex:185 #, elixir-autogen, elixir-format msgid "Number of transactions related to this address." msgstr "" @@ -1894,7 +1909,7 @@ msgstr "" msgid "Number of transfers for the token" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:213 +#: lib/block_scout_web/templates/address/overview.html.eex:212 #, elixir-autogen, elixir-format msgid "Number of transfers to/from this address." msgstr "" @@ -2240,6 +2255,11 @@ msgstr "" msgid "Select Yes if you want to vefify Yul contract." msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19 +#, elixir-autogen, elixir-format +msgid "Select yes if you want to show nightly builds." +msgstr "" + #: lib/block_scout_web/views/internal_transaction_view.ex:27 #, elixir-autogen, elixir-format msgid "Self-Destruct" @@ -2776,7 +2796,7 @@ msgid "Token type" msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:21 -#: lib/block_scout_web/templates/address/overview.html.eex:176 +#: lib/block_scout_web/templates/address/overview.html.eex:175 #: lib/block_scout_web/templates/address_token/overview.html.eex:58 #: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13 #: lib/block_scout_web/templates/layout/_topnav.html.eex:78 @@ -2935,9 +2955,9 @@ msgid "Transaction type, introduced in EIP-2718." msgstr "" #: lib/block_scout_web/templates/address/_tabs.html.eex:7 -#: lib/block_scout_web/templates/address/overview.html.eex:187 -#: lib/block_scout_web/templates/address/overview.html.eex:193 -#: lib/block_scout_web/templates/address/overview.html.eex:201 +#: lib/block_scout_web/templates/address/overview.html.eex:186 +#: lib/block_scout_web/templates/address/overview.html.eex:192 +#: lib/block_scout_web/templates/address/overview.html.eex:200 #: lib/block_scout_web/templates/address_transaction/index.html.eex:13 #: lib/block_scout_web/templates/block/overview.html.eex:80 #: lib/block_scout_web/templates/block_transaction/index.html.eex:10 @@ -2958,9 +2978,9 @@ msgstr "" msgid "Transactions sent" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:214 -#: lib/block_scout_web/templates/address/overview.html.eex:220 -#: lib/block_scout_web/templates/address/overview.html.eex:228 +#: lib/block_scout_web/templates/address/overview.html.eex:213 +#: lib/block_scout_web/templates/address/overview.html.eex:219 +#: lib/block_scout_web/templates/address/overview.html.eex:227 #: lib/block_scout_web/templates/tokens/instance/overview/_details.html.eex:50 #: lib/block_scout_web/templates/tokens/overview/_details.html.eex:119 #, elixir-autogen, elixir-format @@ -2973,6 +2993,11 @@ msgstr "" msgid "Try it out" msgstr "" +#: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:3 +#, elixir-autogen, elixir-format +msgid "Try to fetch constructor arguments automatically" +msgstr "" + #: lib/block_scout_web/templates/layout/_footer.html.eex:27 #, elixir-autogen, elixir-format msgid "Twitter" @@ -3383,7 +3408,7 @@ msgstr "" msgid "custom RPC" msgstr "" -#: lib/block_scout_web/templates/address/overview.html.eex:150 +#: lib/block_scout_web/templates/address/overview.html.eex:149 #, elixir-autogen, elixir-format msgid "doesn't include ERC20, ERC721, ERC1155 tokens)." msgstr "" @@ -3463,28 +3488,3 @@ msgstr "" #, elixir-autogen, elixir-format msgid "truffle flattener" msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:3 -#, elixir-autogen, elixir-format -msgid "Include nightly builds" -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_include_nightly_builds_field.html.eex:19 -#, elixir-autogen, elixir-format -msgid "Select yes if you want to show nightly builds." -msgstr "" - -#: lib/block_scout_web/templates/address_contract_verification_common_fields/_fetch_constructor_args.html.eex:3 -#, elixir-autogen, elixir-format -msgid "Try to fetch constructor arguments automatically" -msgstr "" - -#: lib/block_scout_web/templates/address_contract/index.html.eex:137 -#, elixir-autogen, elixir-format, fuzzy -msgid "Compiler Settings" -msgstr "" - -#: lib/block_scout_web/templates/address_contract/index.html.eex:139 -#, elixir-autogen, elixir-format -msgid "Copy Compiler Settings" -msgstr "" diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex index b8222df2d13e..dc66006f9e80 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/http.ex @@ -3,7 +3,7 @@ defmodule EthereumJSONRPC.HTTP do JSONRPC over HTTP """ - alias EthereumJSONRPC.Transport + alias EthereumJSONRPC.{DecodeError, Transport} require Logger @@ -114,7 +114,17 @@ defmodule EthereumJSONRPC.HTTP do {:error, {:bad_gateway, request_url}} _ -> - raise EthereumJSONRPC.DecodeError, named_arguments + named_arguments + |> DecodeError.exception() + |> DecodeError.message() + |> Logger.error() + + request_url = + named_arguments + |> Keyword.fetch!(:request) + |> Keyword.fetch!(:url) + + {:error, {:bad_response, request_url}} end end end diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/request_coordinator.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/request_coordinator.ex index bd491f25fd7f..b63e0971a6d3 100644 --- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/request_coordinator.ex +++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/request_coordinator.ex @@ -109,7 +109,7 @@ defmodule EthereumJSONRPC.RequestCoordinator do defp trace_request(_, fun), do: fun.() - defp handle_transport_response({:error, {:bad_gateway, _}} = error) do + defp handle_transport_response({:error, {error_type, _}} = error) when error_type in [:bad_gateway, :bad_response] do RollingWindow.inc(table(), @error_key) inc_throttle_table() error diff --git a/apps/explorer/config/test.exs b/apps/explorer/config/test.exs index e9174824ce04..cf55e854ca5b 100644 --- a/apps/explorer/config/test.exs +++ b/apps/explorer/config/test.exs @@ -22,7 +22,11 @@ config :explorer, Explorer.Repo.Replica1, # Default of `5_000` was too low for `BlockFetcher` test ownership_timeout: :timer.minutes(1), timeout: :timer.seconds(60), - queue_target: 1000 + queue_target: 1000, + enable_caching_implementation_data_of_proxy: true, + avg_block_time_as_ttl_cached_implementation_data_of_proxy: false, + fallback_ttl_cached_implementation_data_of_proxy: :timer.seconds(20), + implementation_data_fetching_timeout: :timer.seconds(20) # Configure API database config :explorer, Explorer.Repo.Account, diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index ef481b723220..1d83d1b44ef6 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -21,7 +21,6 @@ defmodule Explorer.Chain do select: 3, subquery: 1, union: 2, - update: 2, where: 2, where: 3 ] @@ -33,7 +32,6 @@ defmodule Explorer.Chain do alias ABI.TypeDecoder alias Ecto.{Changeset, Multi} - alias EthereumJSONRPC.Contract alias EthereumJSONRPC.Transaction, as: EthereumJSONRPCTransaction alias Explorer.Counters.{LastFetchedCounter, TokenHoldersCounter, TokenTransfersCounter} @@ -91,7 +89,7 @@ defmodule Explorer.Chain do alias Explorer.Market.MarketHistoryCache alias Explorer.{PagingOptions, Repo} - alias Explorer.SmartContract.{Helper, Reader} + alias Explorer.SmartContract.Helper alias Dataloader.Ecto, as: DataloaderEcto @@ -4334,13 +4332,28 @@ defmodule Explorer.Chain do Chain.get_address_verified_twin_contract(address_hash).verified_contract if address_verified_twin_contract do - Map.put(address_verified_twin_contract, :address_hash, address_hash) + address_verified_twin_contract + |> Map.put(:address_hash, address_hash) + |> Map.put(:implementation_address_hash, current_smart_contract.implementation_address_hash) + |> Map.put(:implementation_name, current_smart_contract.implementation_name) + |> Map.put(:implementation_fetched_at, current_smart_contract.implementation_fetched_at) else current_smart_contract end end end + @spec address_hash_to_smart_contract_without_twin(Hash.Address.t()) :: SmartContract.t() | nil + def address_hash_to_smart_contract_without_twin(address_hash) do + query = + from( + smart_contract in SmartContract, + where: smart_contract.address_hash == ^address_hash + ) + + Repo.one(query) + end + def smart_contract_fully_verified?(address_hash_str) when is_binary(address_hash_str) do case string_to_address_hash(address_hash_str) do {:ok, address_hash} -> @@ -5844,32 +5857,16 @@ defmodule Explorer.Chain do end end - def combine_proxy_implementation_abi(proxy_address_hash, abi) when not is_nil(abi) do - implementation_abi = get_implementation_abi_from_proxy(proxy_address_hash, abi) + def combine_proxy_implementation_abi(%SmartContract{abi: abi} = smart_contract) when not is_nil(abi) do + implementation_abi = get_implementation_abi_from_proxy(smart_contract) if Enum.empty?(implementation_abi), do: abi, else: implementation_abi ++ abi end - def combine_proxy_implementation_abi(_, abi) when is_nil(abi) do + def combine_proxy_implementation_abi(_) do [] end - def proxy_contract?(address_hash, abi) when not is_nil(abi) do - implementation_method_abi = - abi - |> Enum.find(fn method -> - Map.get(method, "name") == "implementation" || - master_copy_pattern?(method) - end) - - if implementation_method_abi || - get_implementation_address_hash_eip_1967(address_hash) !== "0x0000000000000000000000000000000000000000", - do: true, - else: false - end - - def proxy_contract?(_address_hash, abi) when is_nil(abi), do: false - def gnosis_safe_contract?(abi) when not is_nil(abi) do implementation_method_abi = abi @@ -5882,167 +5879,7 @@ defmodule Explorer.Chain do def gnosis_safe_contract?(abi) when is_nil(abi), do: false - @spec get_implementation_address_hash(Hash.Address.t(), list()) :: {String.t() | nil, String.t() | nil} - def get_implementation_address_hash(proxy_address_hash, abi) - when not is_nil(proxy_address_hash) and not is_nil(abi) do - implementation_method_abi = - abi - |> Enum.find(fn method -> - Map.get(method, "name") == "implementation" && Map.get(method, "stateMutability") == "view" - end) - - master_copy_method_abi = - abi - |> Enum.find(fn method -> - master_copy_pattern?(method) - end) - - implementation_address = - cond do - implementation_method_abi -> - get_implementation_address_hash_basic(proxy_address_hash, abi) - - master_copy_method_abi -> - get_implementation_address_hash_from_master_copy_pattern(proxy_address_hash) - - true -> - get_implementation_address_hash_eip_1967(proxy_address_hash) - end - - save_implementation_name(implementation_address, proxy_address_hash) - end - - def get_implementation_address_hash(proxy_address_hash, abi) when is_nil(proxy_address_hash) or is_nil(abi) do - {nil, nil} - end - - defp get_implementation_address_hash_eip_1967(proxy_address_hash) do - json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) - - # https://eips.ethereum.org/EIPS/eip-1967 - storage_slot_logic_contract_address = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" - - {_status, implementation_address} = - case Contract.eth_get_storage_at_request( - proxy_address_hash, - storage_slot_logic_contract_address, - nil, - json_rpc_named_arguments - ) do - {:ok, empty_address} - when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000"] -> - fetch_beacon_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) - - {:ok, implementation_logic_address} -> - {:ok, implementation_logic_address} - - {:error, _} -> - {:ok, "0x"} - end - - abi_decode_address_output(implementation_address) - end - - # changes requested by https://github.com/blockscout/blockscout/issues/4770 - # for support BeaconProxy pattern - defp fetch_beacon_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) do - # https://eips.ethereum.org/EIPS/eip-1967 - storage_slot_beacon_contract_address = "0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50" - - implementation_method_abi = [ - %{ - "type" => "function", - "stateMutability" => "view", - "outputs" => [%{"type" => "address", "name" => "", "internalType" => "address"}], - "name" => "implementation", - "inputs" => [] - } - ] - - case Contract.eth_get_storage_at_request( - proxy_address_hash, - storage_slot_beacon_contract_address, - nil, - json_rpc_named_arguments - ) do - {:ok, empty_address} - when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000"] -> - fetch_openzeppelin_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) - - {:ok, beacon_contract_address} -> - case beacon_contract_address - |> abi_decode_address_output() - |> get_implementation_address_hash_basic(implementation_method_abi) do - <> -> - {:ok, implementation_address} - - _ -> - {:ok, beacon_contract_address} - end - - {:error, _} -> - {:ok, "0x"} - end - end - - # changes requested by https://github.com/blockscout/blockscout/issues/5292 - defp fetch_openzeppelin_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) do - # This is the keccak-256 hash of "org.zeppelinos.proxy.implementation" - storage_slot_logic_contract_address = "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3" - - case Contract.eth_get_storage_at_request( - proxy_address_hash, - storage_slot_logic_contract_address, - nil, - json_rpc_named_arguments - ) do - {:ok, empty_address} - when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000"] -> - {:ok, "0x"} - - {:ok, logic_contract_address} -> - {:ok, logic_contract_address} - - {:error, _} -> - {:ok, "0x"} - end - end - - defp get_implementation_address_hash_basic(proxy_address_hash, abi) do - # 5c60da1b = keccak256(implementation()) - implementation_address = - case Reader.query_contract( - proxy_address_hash, - abi, - %{ - "5c60da1b" => [] - }, - false - ) do - %{"5c60da1b" => {:ok, [result]}} -> result - _ -> nil - end - - address_to_hex(implementation_address) - end - - defp get_implementation_address_hash_from_master_copy_pattern(proxy_address_hash) do - json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) - - master_copy_storage_pointer = "0x0" - - {:ok, implementation_address} = - Contract.eth_get_storage_at_request( - proxy_address_hash, - master_copy_storage_pointer, - nil, - json_rpc_named_arguments - ) - - abi_decode_address_output(implementation_address) - end - - defp master_copy_pattern?(method) do + def master_copy_pattern?(method) do Map.get(method, "type") == "constructor" && method |> Enum.find(fn item -> @@ -6063,57 +5900,6 @@ defmodule Explorer.Chain do end) end - defp save_implementation_name(empty_address_hash_string, _) - when empty_address_hash_string in [ - "0x", - "0x0", - "0x0000000000000000000000000000000000000000000000000000000000000000", - @burn_address_hash_str - ], - do: {empty_address_hash_string, nil} - - defp save_implementation_name(implementation_address_hash_string, proxy_address_hash) - when is_binary(implementation_address_hash_string) do - with {:ok, address_hash} <- string_to_address_hash(implementation_address_hash_string), - %SmartContract{name: name} <- address_hash_to_smart_contract(address_hash) do - SmartContract - |> where([sc], sc.address_hash == ^proxy_address_hash) - |> update(set: [implementation_name: ^name]) - |> Repo.update_all([]) - - {implementation_address_hash_string, name} - else - _ -> - {implementation_address_hash_string, nil} - end - end - - defp save_implementation_name(other, _), do: {other, nil} - - defp abi_decode_address_output(nil), do: nil - - defp abi_decode_address_output("0x"), do: @burn_address_hash_str - - defp abi_decode_address_output(address) when is_binary(address) do - if String.length(address) > 42 do - "0x" <> String.slice(address, -40, 40) - else - address - end - end - - defp abi_decode_address_output(_), do: nil - - defp address_to_hex(address) do - if address do - if String.starts_with?(address, "0x") do - address - else - "0x" <> Base.encode16(address, case: :lower) - end - end - end - def get_implementation_abi(implementation_address_hash_string) when not is_nil(implementation_address_hash_string) do case Chain.string_to_address_hash(implementation_address_hash_string) do {:ok, implementation_address_hash} -> @@ -6137,15 +5923,13 @@ defmodule Explorer.Chain do [] end - def get_implementation_abi_from_proxy(proxy_address_hash, abi) + def get_implementation_abi_from_proxy(%SmartContract{address_hash: proxy_address_hash, abi: abi} = smart_contract) when not is_nil(proxy_address_hash) and not is_nil(abi) do - {implementation_address_hash_string, _name} = get_implementation_address_hash(proxy_address_hash, abi) + {implementation_address_hash_string, _name} = SmartContract.get_implementation_address_hash(smart_contract) get_implementation_abi(implementation_address_hash_string) end - def get_implementation_abi_from_proxy(proxy_address_hash, abi) when is_nil(proxy_address_hash) or is_nil(abi) do - [] - end + def get_implementation_abi_from_proxy(_), do: [] defp format_tx_first_trace(first_trace, block_hash, json_rpc_named_arguments) do {:ok, to_address_hash} = diff --git a/apps/explorer/lib/explorer/chain/log.ex b/apps/explorer/lib/explorer/chain/log.ex index f9de1eb43d95..4a2381888195 100644 --- a/apps/explorer/lib/explorer/chain/log.ex +++ b/apps/explorer/lib/explorer/chain/log.ex @@ -128,8 +128,8 @@ defmodule Explorer.Chain.Log do ] case Chain.find_contract_address(log.address_hash, address_options, true) do - {:ok, %{smart_contract: %{abi: abi}}} -> - full_abi = Chain.combine_proxy_implementation_abi(log.address_hash, abi) + {:ok, %{smart_contract: smart_contract}} -> + full_abi = Chain.combine_proxy_implementation_abi(smart_contract) with {:ok, selector, mapping} <- find_and_decode(full_abi, log, transaction), identifier <- Base.encode16(selector.method_id, case: :lower), diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index 0b18c8a3e43c..bd72f3ad2b86 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -13,9 +13,15 @@ defmodule Explorer.Chain.SmartContract do use Explorer.Schema alias Ecto.Changeset + alias EthereumJSONRPC.Contract + alias Explorer.Counters.AverageBlockTime alias Explorer.{Chain, Repo} alias Explorer.Chain.{Address, ContractMethod, DecompiledSmartContract, Hash} alias Explorer.Chain.SmartContract.ExternalLibrary + alias Explorer.SmartContract.Reader + alias Timex.Duration + + @burn_address_hash_str "0x0000000000000000000000000000000000000000" @typedoc """ The name of a parameter to a function or event. @@ -201,7 +207,9 @@ defmodule Explorer.Chain.SmartContract do * `bytecode_checked_at` - timestamp of the last check of contract's bytecode matching (DB and BlockChain) * `contract_code_md5` - md5(`t:Explorer.Chain.Address.t/0` `contract_code`) * `implementation_name` - name of the proxy implementation - * `settings` - raw compilation parameters + * `compiler_settings` - raw compilation parameters + * `implementation_fetched_at` - timestamp of the last fetching contract's implementation info + * `implementation_address_hash` - address hash of the proxy's implementation if any * `autodetect_constructor_args` - field was added for storing user's choice * `is_yul` - field was added for storing user's choice """ @@ -224,6 +232,8 @@ defmodule Explorer.Chain.SmartContract do contract_code_md5: String.t(), implementation_name: String.t() | nil, compiler_settings: map() | nil, + implementation_fetched_at: DateTime.t(), + implementation_address_hash: Hash.Address.t(), autodetect_constructor_args: boolean | nil, is_yul: boolean | nil } @@ -247,6 +257,8 @@ defmodule Explorer.Chain.SmartContract do field(:contract_code_md5, :string) field(:implementation_name, :string) field(:compiler_settings, :map) + field(:implementation_fetched_at, :utc_datetime_usec, default: nil) + field(:implementation_address_hash, Hash.Address, default: nil) field(:autodetect_constructor_args, :boolean, virtual: true) field(:is_yul, :boolean, virtual: true) @@ -291,7 +303,9 @@ defmodule Explorer.Chain.SmartContract do :bytecode_checked_at, :contract_code_md5, :implementation_name, - :compiler_settings + :compiler_settings, + :implementation_address_hash, + :implementation_fetched_at ]) |> validate_required([ :name, @@ -493,4 +507,370 @@ defmodule Explorer.Chain.SmartContract do end defp to_address_hash(address_hash), do: address_hash + + def proxy_contract?(%__MODULE__{abi: abi} = smart_contract) when not is_nil(abi) do + implementation_method_abi = + abi + |> Enum.find(fn method -> + Map.get(method, "name") == "implementation" || + Chain.master_copy_pattern?(method) + end) + + if implementation_method_abi || + not is_nil( + smart_contract + |> get_implementation_address_hash() + |> Tuple.to_list() + |> List.first() + ), + do: true, + else: false + end + + def proxy_contract?(_), do: false + + def get_implementation_address_hash(%__MODULE__{abi: nil}), do: false + + def get_implementation_address_hash( + %__MODULE__{ + address_hash: address_hash, + implementation_fetched_at: implementation_fetched_at + } = smart_contract + ) do + updated_smart_contract = + if Application.get_env(:explorer, :enable_caching_implementation_data_of_proxy) && + check_implementation_refetch_neccessity(implementation_fetched_at) do + Chain.address_hash_to_smart_contract(address_hash) + else + smart_contract + end + + get_implementation_address_hash({:updated, updated_smart_contract}) + end + + def get_implementation_address_hash( + {:updated, + %__MODULE__{ + address_hash: address_hash, + abi: abi, + implementation_address_hash: implementation_address_hash_from_db, + implementation_name: implementation_name_from_db, + implementation_fetched_at: implementation_fetched_at + }} + ) do + if check_implementation_refetch_neccessity(implementation_fetched_at) do + get_implementation_address_hash_task = Task.async(fn -> get_implementation_address_hash(address_hash, abi) end) + + timeout = Application.get_env(:explorer, :implementation_data_fetching_timeout) + + case Task.yield(get_implementation_address_hash_task, timeout) || + Task.ignore(get_implementation_address_hash_task) do + {:ok, {:empty, :empty}} -> + {nil, nil} + + {:ok, {address_hash, _name} = result} when not is_nil(address_hash) -> + result + + _ -> + {db_implementation_data_converter(implementation_address_hash_from_db), + db_implementation_data_converter(implementation_name_from_db)} + end + else + {db_implementation_data_converter(implementation_address_hash_from_db), + db_implementation_data_converter(implementation_name_from_db)} + end + end + + def get_implementation_address_hash(_), do: {nil, nil} + + defp db_implementation_data_converter(nil), do: nil + defp db_implementation_data_converter(string) when is_binary(string), do: string + defp db_implementation_data_converter(other), do: to_string(other) + + defp check_implementation_refetch_neccessity(nil), do: true + + defp check_implementation_refetch_neccessity(timestamp) do + if Application.get_env(:explorer, :enable_caching_implementation_data_of_proxy) do + now = DateTime.utc_now() + + average_block_time = + if Application.get_env(:explorer, :avg_block_time_as_ttl_cached_implementation_data_of_proxy) do + case AverageBlockTime.average_block_time() do + {:error, :disabled} -> + 0 + + duration -> + duration + |> Duration.to_milliseconds() + end + else + 0 + end + + fresh_time_distance = + case average_block_time do + 0 -> + Application.get_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy) + + time -> + round(time) + end + + timestamp + |> DateTime.add(fresh_time_distance, :millisecond) + |> DateTime.compare(now) != :gt + else + true + end + end + + @spec get_implementation_address_hash(Hash.Address.t(), list()) :: {String.t() | nil, String.t() | nil} + defp get_implementation_address_hash(proxy_address_hash, abi) + when not is_nil(proxy_address_hash) and not is_nil(abi) do + implementation_method_abi = + abi + |> Enum.find(fn method -> + Map.get(method, "name") == "implementation" && Map.get(method, "stateMutability") == "view" + end) + + master_copy_method_abi = + abi + |> Enum.find(fn method -> + Chain.master_copy_pattern?(method) + end) + + implementation_address = + cond do + implementation_method_abi -> + get_implementation_address_hash_basic(proxy_address_hash, abi) + + master_copy_method_abi -> + get_implementation_address_hash_from_master_copy_pattern(proxy_address_hash) + + true -> + get_implementation_address_hash_eip_1967(proxy_address_hash) + end + + save_implementation_data(implementation_address, proxy_address_hash) + end + + defp get_implementation_address_hash(proxy_address_hash, abi) when is_nil(proxy_address_hash) or is_nil(abi) do + {nil, nil} + end + + defp get_implementation_address_hash_eip_1967(proxy_address_hash) do + json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) + + # https://eips.ethereum.org/EIPS/eip-1967 + storage_slot_logic_contract_address = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc" + + {_status, implementation_address} = + case Contract.eth_get_storage_at_request( + proxy_address_hash, + storage_slot_logic_contract_address, + nil, + json_rpc_named_arguments + ) do + {:ok, empty_address} + when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000", nil] -> + fetch_beacon_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) + + {:ok, implementation_logic_address} -> + {:ok, implementation_logic_address} + + _ -> + {:ok, nil} + end + + abi_decode_address_output(implementation_address) + end + + # changes requested by https://github.com/blockscout/blockscout/issues/4770 + # for support BeaconProxy pattern + defp fetch_beacon_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) do + # https://eips.ethereum.org/EIPS/eip-1967 + storage_slot_beacon_contract_address = "0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50" + + implementation_method_abi = [ + %{ + "type" => "function", + "stateMutability" => "view", + "outputs" => [%{"type" => "address", "name" => "", "internalType" => "address"}], + "name" => "implementation", + "inputs" => [] + } + ] + + case Contract.eth_get_storage_at_request( + proxy_address_hash, + storage_slot_beacon_contract_address, + nil, + json_rpc_named_arguments + ) do + {:ok, empty_address} + when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000", nil] -> + fetch_openzeppelin_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) + + {:ok, beacon_contract_address} -> + case beacon_contract_address + |> abi_decode_address_output() + |> get_implementation_address_hash_basic(implementation_method_abi) do + <> -> + {:ok, implementation_address} + + _ -> + {:ok, beacon_contract_address} + end + + _ -> + {:ok, nil} + end + end + + # changes requested by https://github.com/blockscout/blockscout/issues/5292 + defp fetch_openzeppelin_proxy_implementation(proxy_address_hash, json_rpc_named_arguments) do + # This is the keccak-256 hash of "org.zeppelinos.proxy.implementation" + storage_slot_logic_contract_address = "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3" + + case Contract.eth_get_storage_at_request( + proxy_address_hash, + storage_slot_logic_contract_address, + nil, + json_rpc_named_arguments + ) do + {:ok, empty_address} + when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000"] -> + {:ok, "0x"} + + {:ok, logic_contract_address} -> + {:ok, logic_contract_address} + + _ -> + {:ok, nil} + end + end + + defp get_implementation_address_hash_basic(proxy_address_hash, abi) do + # 5c60da1b = keccak256(implementation()) + implementation_address = + case Reader.query_contract( + proxy_address_hash, + abi, + %{ + "5c60da1b" => [] + }, + false + ) do + %{"5c60da1b" => {:ok, [result]}} -> result + _ -> nil + end + + address_to_hex(implementation_address) + end + + defp get_implementation_address_hash_from_master_copy_pattern(proxy_address_hash) do + json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments) + + master_copy_storage_pointer = "0x0" + + {:ok, implementation_address} = + case Contract.eth_get_storage_at_request( + proxy_address_hash, + master_copy_storage_pointer, + nil, + json_rpc_named_arguments + ) do + {:ok, empty_address} + when empty_address in ["0x", "0x0", "0x0000000000000000000000000000000000000000000000000000000000000000"] -> + {:ok, "0x"} + + {:ok, logic_contract_address} -> + {:ok, logic_contract_address} + + _ -> + {:ok, nil} + end + + abi_decode_address_output(implementation_address) + end + + defp save_implementation_data(nil, _), do: {nil, nil} + + defp save_implementation_data(empty_address_hash_string, proxy_address_hash) + when empty_address_hash_string in [ + "0x", + "0x0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + @burn_address_hash_str + ] do + proxy_address_hash + |> Chain.address_hash_to_smart_contract_without_twin() + |> changeset(%{ + implementation_name: nil, + implementation_address_hash: nil, + implementation_fetched_at: DateTime.utc_now() + }) + |> Repo.update() + + {:empty, :empty} + end + + defp save_implementation_data(implementation_address_hash_string, proxy_address_hash) + when is_binary(implementation_address_hash_string) do + with {:ok, address_hash} <- Chain.string_to_address_hash(implementation_address_hash_string), + proxy_contract <- Chain.address_hash_to_smart_contract_without_twin(proxy_address_hash), + false <- is_nil(proxy_contract), + %{implementation: %__MODULE__{name: name}, proxy: proxy_contract} <- %{ + implementation: Chain.address_hash_to_smart_contract(address_hash), + proxy: proxy_contract + } do + proxy_contract + |> changeset(%{ + implementation_name: name, + implementation_address_hash: implementation_address_hash_string, + implementation_fetched_at: DateTime.utc_now() + }) + |> Repo.update() + + {implementation_address_hash_string, name} + else + %{implementation: _, proxy: proxy_contract} -> + proxy_contract + |> changeset(%{ + implementation_name: nil, + implementation_address_hash: implementation_address_hash_string, + implementation_fetched_at: DateTime.utc_now() + }) + |> Repo.update() + + {implementation_address_hash_string, nil} + + _ -> + {implementation_address_hash_string, nil} + end + end + + defp address_to_hex(address) do + if address do + if String.starts_with?(address, "0x") do + address + else + "0x" <> Base.encode16(address, case: :lower) + end + end + end + + defp abi_decode_address_output(nil), do: nil + + defp abi_decode_address_output("0x"), do: @burn_address_hash_str + + defp abi_decode_address_output(address) when is_binary(address) do + if String.length(address) > 42 do + "0x" <> String.slice(address, -40, 40) + else + address + end + end + + defp abi_decode_address_output(_), do: nil end diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex index be55eba91d76..0dccd1c90f90 100644 --- a/apps/explorer/lib/explorer/chain/transaction.ex +++ b/apps/explorer/lib/explorer/chain/transaction.ex @@ -23,6 +23,7 @@ defmodule Explorer.Chain.Transaction do Hash, InternalTransaction, Log, + SmartContract, TokenTransfer, Transaction, Wei @@ -493,7 +494,7 @@ defmodule Explorer.Chain.Transaction do candidates_query |> Repo.all() |> Enum.flat_map(fn candidate -> - case do_decoded_input_data(data, [candidate.abi], nil, hash) do + case do_decoded_input_data(data, %SmartContract{abi: [candidate.abi], address_hash: nil}, hash) do {:ok, _, _, _} = decoded -> [decoded] _ -> [] end @@ -508,11 +509,11 @@ defmodule Explorer.Chain.Transaction do def decoded_input_data(%__MODULE__{ input: %{bytes: data}, - to_address: %{smart_contract: %{abi: abi, address_hash: address_hash}}, + to_address: %{smart_contract: smart_contract}, hash: hash }) do - case do_decoded_input_data(data, abi, address_hash, hash) do - # In some cases transactions use methods of some unpredictable contracts, so we can try to look up for method in a whole DB + case do_decoded_input_data(data, smart_contract, hash) do + # In some cases transactions use methods of some unpredictadle contracts, so we can try to look up for method in a whole DB {:error, :could_not_decode} -> case decoded_input_data(%__MODULE__{ to_address: %{smart_contract: nil}, @@ -534,8 +535,8 @@ defmodule Explorer.Chain.Transaction do end end - defp do_decoded_input_data(data, abi, address_hash, hash) do - full_abi = Chain.combine_proxy_implementation_abi(address_hash, abi) + defp do_decoded_input_data(data, smart_contract, hash) do + full_abi = Chain.combine_proxy_implementation_abi(smart_contract) with {:ok, {selector, values}} <- find_and_decode(full_abi, data, hash), {:ok, mapping} <- selector_mapping(selector, values, hash), diff --git a/apps/explorer/lib/explorer/etherscan/contracts.ex b/apps/explorer/lib/explorer/etherscan/contracts.ex index a02f791af7a8..cea04475df1d 100644 --- a/apps/explorer/lib/explorer/etherscan/contracts.ex +++ b/apps/explorer/lib/explorer/etherscan/contracts.ex @@ -60,13 +60,13 @@ defmodule Explorer.Etherscan.Contracts do def append_proxy_info(%Address{smart_contract: smart_contract} = address) when not is_nil(smart_contract) do updated_smart_contract = - if Chain.proxy_contract?(address.hash, smart_contract.abi) do + if SmartContract.proxy_contract?(smart_contract) do smart_contract |> Map.put(:is_proxy, true) |> Map.put( :implementation_address_hash_string, - address.hash - |> Chain.get_implementation_address_hash(smart_contract.abi) + smart_contract + |> SmartContract.get_implementation_address_hash() |> Tuple.to_list() |> List.first() ) diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex index d83cdc2c4ad3..0d0c8d5b2dce 100644 --- a/apps/explorer/lib/explorer/smart_contract/reader.ex +++ b/apps/explorer/lib/explorer/smart_contract/reader.ex @@ -526,15 +526,12 @@ defmodule Explorer.SmartContract.Reader do end defp get_abi(contract_address_hash, type) do - abi = - contract_address_hash - |> Chain.address_hash_to_smart_contract() - |> Map.get(:abi) + contract = Chain.address_hash_to_smart_contract(contract_address_hash) if type == :proxy do - Chain.get_implementation_abi_from_proxy(contract_address_hash, abi) + Chain.get_implementation_abi_from_proxy(contract) else - abi + contract.abi end end diff --git a/apps/explorer/priv/repo/migrations/20220527131249_add_implementation_fields.exs b/apps/explorer/priv/repo/migrations/20220527131249_add_implementation_fields.exs new file mode 100644 index 000000000000..5f3839dd4a4c --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20220527131249_add_implementation_fields.exs @@ -0,0 +1,10 @@ +defmodule Explorer.Repo.Migrations.AddImplementationFields do + use Ecto.Migration + + def change do + alter table(:smart_contracts) do + add(:implementation_address_hash, :bytea, null: true) + add(:implementation_fetched_at, :"timestamp without time zone", null: true) + end + end +end diff --git a/apps/explorer/test/explorer/chain/smart_contract_test.exs b/apps/explorer/test/explorer/chain/smart_contract_test.exs new file mode 100644 index 000000000000..38ff09e3b1e3 --- /dev/null +++ b/apps/explorer/test/explorer/chain/smart_contract_test.exs @@ -0,0 +1,237 @@ +defmodule Explorer.Chain.SmartContractTest do + use Explorer.DataCase, async: false + + import Mox + alias Explorer.Chain + alias Explorer.Chain.SmartContract + + doctest Explorer.Chain.SmartContract + + setup :verify_on_exit! + setup :set_mox_global + + describe "test fetching implementation" do + test "check proxy_contract/1 function" do + smart_contract = insert(:smart_contract) + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) + Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) + + refute smart_contract.implementation_fetched_at + + # fetch nil implementation and save it to db + get_eip1967_implementation_zero_addresses() + refute SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + assert_empty_implementation(smart_contract.address_hash) + # extract proxy info from db + refute SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + assert_empty_implementation(smart_contract.address_hash) + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) + + get_eip1967_implementation_error_response() + refute SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + + get_eip1967_implementation_non_zero_address() + assert SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + assert_implementation_address(smart_contract.address_hash) + + get_eip1967_implementation_non_zero_address() + assert SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + assert_implementation_address(smart_contract.address_hash) + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) + assert SmartContract.proxy_contract?(smart_contract) + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) + get_eip1967_implementation_non_zero_address() + assert SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + + get_eip1967_implementation_error_response() + assert SmartContract.proxy_contract?(smart_contract) + verify!(EthereumJSONRPC.Mox) + end + + test "test get_implementation_adddress_hash/1" do + smart_contract = insert(:smart_contract) + implementation_smart_contract = insert(:smart_contract, name: "proxy") + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) + Application.put_env(:explorer, :implementation_data_fetching_timeout, :timer.seconds(20)) + + refute smart_contract.implementation_fetched_at + + # fetch nil implementation and save it to db + get_eip1967_implementation_zero_addresses() + assert {nil, nil} = SmartContract.get_implementation_address_hash(smart_contract) + verify!(EthereumJSONRPC.Mox) + assert_empty_implementation(smart_contract.address_hash) + + # extract proxy info from db + assert {nil, nil} = SmartContract.get_implementation_address_hash(smart_contract) + assert_empty_implementation(smart_contract.address_hash) + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) + + string_implementation_address_hash = to_string(implementation_smart_contract.address_hash) + + expect(EthereumJSONRPC.Mox, :json_rpc, fn %{ + id: 0, + method: "eth_getStorageAt", + params: [ + _, + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + "latest" + ] + }, + _options -> + {:ok, string_implementation_address_hash} + end) + + assert {^string_implementation_address_hash, "proxy"} = + SmartContract.get_implementation_address_hash(smart_contract) + + verify!(EthereumJSONRPC.Mox) + + assert_exact_name_and_address( + smart_contract.address_hash, + implementation_smart_contract.address_hash, + implementation_smart_contract.name + ) + + get_eip1967_implementation_error_response() + + assert {^string_implementation_address_hash, "proxy"} = + SmartContract.get_implementation_address_hash(smart_contract) + + verify!(EthereumJSONRPC.Mox) + + assert_exact_name_and_address( + smart_contract.address_hash, + implementation_smart_contract.address_hash, + implementation_smart_contract.name + ) + + contract_1 = Chain.address_hash_to_smart_contract(smart_contract.address_hash) + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, :timer.seconds(20)) + + assert {^string_implementation_address_hash, "proxy"} = + SmartContract.get_implementation_address_hash(smart_contract) + + contract_2 = Chain.address_hash_to_smart_contract(smart_contract.address_hash) + + assert contract_1.implementation_fetched_at == contract_2.implementation_fetched_at && + contract_1.updated_at == contract_2.updated_at + + Application.put_env(:explorer, :fallback_ttl_cached_implementation_data_of_proxy, 0) + get_eip1967_implementation_zero_addresses() + assert {nil, nil} = SmartContract.get_implementation_address_hash(smart_contract) + verify!(EthereumJSONRPC.Mox) + assert_empty_implementation(smart_contract.address_hash) + end + end + + def get_eip1967_implementation_zero_addresses do + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn %{ + id: 0, + method: "eth_getStorageAt", + params: [ + _, + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + "latest" + ] + }, + _options -> + {:ok, "0x0000000000000000000000000000000000000000000000000000000000000000"} + end) + |> expect(:json_rpc, fn %{ + id: 0, + method: "eth_getStorageAt", + params: [ + _, + "0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50", + "latest" + ] + }, + _options -> + {:ok, "0x0000000000000000000000000000000000000000000000000000000000000000"} + end) + |> expect(:json_rpc, fn %{ + id: 0, + method: "eth_getStorageAt", + params: [ + _, + "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3", + "latest" + ] + }, + _options -> + {:ok, "0x0000000000000000000000000000000000000000000000000000000000000000"} + end) + end + + def get_eip1967_implementation_non_zero_address do + expect(EthereumJSONRPC.Mox, :json_rpc, fn %{ + id: 0, + method: "eth_getStorageAt", + params: [ + _, + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + "latest" + ] + }, + _options -> + {:ok, "0x0000000000000000000000000000000000000000000000000000000000000001"} + end) + end + + def get_eip1967_implementation_error_response do + EthereumJSONRPC.Mox + |> expect(:json_rpc, fn %{ + id: 0, + method: "eth_getStorageAt", + params: [ + _, + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc", + "latest" + ] + }, + _options -> + {:error, "error"} + end) + end + + def assert_empty_implementation(address_hash) do + contract = Chain.address_hash_to_smart_contract(address_hash) + assert contract.implementation_fetched_at + refute contract.implementation_name + refute contract.implementation_address_hash + end + + def assert_implementation_address(address_hash) do + contract = Chain.address_hash_to_smart_contract(address_hash) + assert contract.implementation_fetched_at + assert contract.implementation_address_hash + end + + def assert_implementation_name(address_hash) do + contract = Chain.address_hash_to_smart_contract(address_hash) + assert contract.implementation_fetched_at + assert contract.implementation_name + end + + def assert_exact_name_and_address(address_hash, implementation_address_hash, implementation_name) do + contract = Chain.address_hash_to_smart_contract(address_hash) + assert contract.implementation_fetched_at + assert contract.implementation_name == implementation_name + assert to_string(contract.implementation_address_hash) == to_string(implementation_address_hash) + end +end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index 61b42a0e6002..dfad452986bd 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -5936,26 +5936,36 @@ defmodule Explorer.ChainTest do test "combine_proxy_implementation_abi/2 returns empty [] abi if proxy abi is null" do proxy_contract_address = insert(:contract_address) - assert Chain.combine_proxy_implementation_abi(proxy_contract_address, nil) == [] + + assert Chain.combine_proxy_implementation_abi(%SmartContract{address_hash: proxy_contract_address.hash, abi: nil}) == + [] end test "combine_proxy_implementation_abi/2 returns [] abi for unverified proxy" do proxy_contract_address = insert(:contract_address) + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: [], contract_code_md5: "123") + get_eip1967_implementation() - assert Chain.combine_proxy_implementation_abi(proxy_contract_address, []) == [] + assert Chain.combine_proxy_implementation_abi(smart_contract) == [] end test "combine_proxy_implementation_abi/2 returns proxy abi if implementation is not verified" do proxy_contract_address = insert(:contract_address) - insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") - assert Chain.combine_proxy_implementation_abi(proxy_contract_address, @proxy_abi) == @proxy_abi + + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") + + assert Chain.combine_proxy_implementation_abi(smart_contract) == @proxy_abi end test "combine_proxy_implementation_abi/2 returns proxy + implementation abi if implementation is verified" do proxy_contract_address = insert(:contract_address) - insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") + + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") implementation_contract_address = insert(:contract_address) @@ -5983,7 +5993,7 @@ defmodule Explorer.ChainTest do end ) - combined_abi = Chain.combine_proxy_implementation_abi(proxy_contract_address.hash, @proxy_abi) + combined_abi = Chain.combine_proxy_implementation_abi(smart_contract) assert Enum.any?(@proxy_abi, fn el -> el == Enum.at(@implementation_abi, 0) end) == false assert Enum.any?(@proxy_abi, fn el -> el == Enum.at(@implementation_abi, 1) end) == false @@ -5993,26 +6003,36 @@ defmodule Explorer.ChainTest do test "get_implementation_abi_from_proxy/2 returns empty [] abi if proxy abi is null" do proxy_contract_address = insert(:contract_address) - assert Chain.get_implementation_abi_from_proxy(proxy_contract_address, nil) == [] + + assert Chain.get_implementation_abi_from_proxy(%SmartContract{address_hash: proxy_contract_address.hash, abi: nil}) == + [] end test "get_implementation_abi_from_proxy/2 returns [] abi for unverified proxy" do proxy_contract_address = insert(:contract_address) + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: [], contract_code_md5: "123") + get_eip1967_implementation() - assert Chain.combine_proxy_implementation_abi(proxy_contract_address, []) == [] + assert Chain.combine_proxy_implementation_abi(smart_contract) == [] end test "get_implementation_abi_from_proxy/2 returns [] if implementation is not verified" do proxy_contract_address = insert(:contract_address) - insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") - assert Chain.get_implementation_abi_from_proxy(proxy_contract_address, @proxy_abi) == [] + + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") + + assert Chain.get_implementation_abi_from_proxy(smart_contract) == [] end test "get_implementation_abi_from_proxy/2 returns implementation abi if implementation is verified" do proxy_contract_address = insert(:contract_address) - insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") + + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: @proxy_abi, contract_code_md5: "123") implementation_contract_address = insert(:contract_address) @@ -6040,14 +6060,16 @@ defmodule Explorer.ChainTest do end ) - implementation_abi = Chain.get_implementation_abi_from_proxy(proxy_contract_address.hash, @proxy_abi) + implementation_abi = Chain.get_implementation_abi_from_proxy(smart_contract) assert implementation_abi == @implementation_abi end test "get_implementation_abi_from_proxy/2 returns implementation abi in case of EIP-1967 proxy pattern" do proxy_contract_address = insert(:contract_address) - insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: [], contract_code_md5: "123") + + smart_contract = + insert(:smart_contract, address_hash: proxy_contract_address.hash, abi: [], contract_code_md5: "123") implementation_contract_address = insert(:contract_address) @@ -6077,7 +6099,7 @@ defmodule Explorer.ChainTest do end ) - implementation_abi = Chain.get_implementation_abi_from_proxy(proxy_contract_address.hash, []) + implementation_abi = Chain.get_implementation_abi_from_proxy(smart_contract) assert implementation_abi == @implementation_abi end diff --git a/config/runtime.exs b/config/runtime.exs index d3b31abf7e25..7b9777f13fb0 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -213,7 +213,11 @@ config :explorer, if(disable_webapp != "true", do: Explorer.Chain.Events.SimpleSender, else: Explorer.Chain.Events.DBSender - ) + ), + enable_caching_implementation_data_of_proxy: true, + avg_block_time_as_ttl_cached_implementation_data_of_proxy: true, + fallback_ttl_cached_implementation_data_of_proxy: :timer.seconds(4), + implementation_data_fetching_timeout: :timer.seconds(2) config :explorer, Explorer.Visualize.Sol2uml, service_url: System.get_env("VISUALIZE_SOL2UML_SERVICE_URL"), From 5ec5ec94a9f0b248253ef94f129a62736351d999 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:16:28 +0000 Subject: [PATCH 54/66] Bump photoswipe from 5.3.3 to 5.3.4 in /apps/block_scout_web/assets Bumps [photoswipe](https://github.com/dimsemenov/Photoswipe) from 5.3.3 to 5.3.4. - [Release notes](https://github.com/dimsemenov/Photoswipe/releases) - [Commits](https://github.com/dimsemenov/Photoswipe/compare/v5.3.3...v5.3.4) --- updated-dependencies: - dependency-name: photoswipe dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 19 +++++++++---------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index bd616a3a1d1b..aaea3a7dd0df 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -51,7 +51,7 @@ "path-parser": "^6.1.0", "phoenix": "file:../../../deps/phoenix", "phoenix_html": "file:../../../deps/phoenix_html", - "photoswipe": "^5.3.3", + "photoswipe": "^5.3.4", "pikaday": "^1.8.2", "popper.js": "^1.14.7", "reduce-reducers": "^1.0.4", @@ -98,11 +98,10 @@ } }, "../../../deps/phoenix": { - "version": "1.5.13", - "license": "MIT" + "version": "0.0.1" }, "../../../deps/phoenix_html": { - "version": "3.0.4" + "version": "0.0.1" }, "node_modules/@ampproject/remapping": { "version": "2.2.0", @@ -14028,9 +14027,9 @@ "link": true }, "node_modules/photoswipe": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.3.tgz", - "integrity": "sha512-BUuulwZwkYFKADSe5xf0dd+wf6dws34ZvqP8R3oYHepRauOXoQHvw600sw1HlWd8K0S3LRCS4jxyR5fTuI383Q==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.4.tgz", + "integrity": "sha512-SN+RWHqxJvdwzXJsh8KrG+ajjPpdTX5HpKglEd0k9o6o5fW+QHPkW8//Bo11MB+NQwTa/hFw8BDv2EdxiDXjNw==", "engines": { "node": ">= 0.12.0" } @@ -29192,9 +29191,9 @@ "version": "file:../../../deps/phoenix_html" }, "photoswipe": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.3.tgz", - "integrity": "sha512-BUuulwZwkYFKADSe5xf0dd+wf6dws34ZvqP8R3oYHepRauOXoQHvw600sw1HlWd8K0S3LRCS4jxyR5fTuI383Q==" + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.4.tgz", + "integrity": "sha512-SN+RWHqxJvdwzXJsh8KrG+ajjPpdTX5HpKglEd0k9o6o5fW+QHPkW8//Bo11MB+NQwTa/hFw8BDv2EdxiDXjNw==" }, "picocolors": { "version": "1.0.0", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index b066d3788021..afe71003246c 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -63,7 +63,7 @@ "path-parser": "^6.1.0", "phoenix": "file:../../../deps/phoenix", "phoenix_html": "file:../../../deps/phoenix_html", - "photoswipe": "^5.3.3", + "photoswipe": "^5.3.4", "pikaday": "^1.8.2", "popper.js": "^1.14.7", "reduce-reducers": "^1.0.4", From 4acfd4af642f8de4de2b3139928118782828befd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Nov 2022 18:17:22 +0000 Subject: [PATCH 55/66] Bump @babel/core from 7.20.2 to 7.20.5 in /apps/block_scout_web/assets Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.20.2 to 7.20.5. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.20.5/packages/babel-core) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 123 +++++++++--------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 62 insertions(+), 63 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index bd616a3a1d1b..3fe7a6e931ff 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -68,7 +68,7 @@ "xss": "^1.0.14" }, "devDependencies": { - "@babel/core": "^7.20.2", + "@babel/core": "^7.20.5", "@babel/preset-env": "^7.20.2", "autoprefixer": "^10.4.13", "babel-loader": "^9.1.0", @@ -98,11 +98,10 @@ } }, "../../../deps/phoenix": { - "version": "1.5.13", - "license": "MIT" + "version": "0.0.1" }, "../../../deps/phoenix_html": { - "version": "3.0.4" + "version": "0.0.1" }, "node_modules/@ampproject/remapping": { "version": "2.2.0", @@ -148,20 +147,20 @@ } }, "node_modules/@babel/core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", - "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", + "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.2", + "@babel/generator": "^7.20.5", "@babel/helper-compilation-targets": "^7.20.0", "@babel/helper-module-transforms": "^7.20.2", - "@babel/helpers": "^7.20.1", - "@babel/parser": "^7.20.2", + "@babel/helpers": "^7.20.5", + "@babel/parser": "^7.20.5", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -177,11 +176,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.3.tgz", - "integrity": "sha512-Wl5ilw2UD1+ZYprHVprxHZJCFeBWlzZYOovE4SDYLZnqCOD11j+0QzNeEWKLLTWM7nixrZEh7vNIyb76MyJg3A==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "dependencies": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -495,13 +494,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", - "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", + "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", "dependencies": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.0" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" }, "engines": { "node": ">=6.9.0" @@ -521,9 +520,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1737,18 +1736,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", - "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", + "@babel/generator": "^7.20.5", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1757,9 +1756,9 @@ } }, "node_modules/@babel/types": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", - "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -18572,20 +18571,20 @@ "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==" }, "@babel/core": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", - "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz", + "integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.2", + "@babel/generator": "^7.20.5", "@babel/helper-compilation-targets": "^7.20.0", "@babel/helper-module-transforms": "^7.20.2", - "@babel/helpers": "^7.20.1", - "@babel/parser": "^7.20.2", + "@babel/helpers": "^7.20.5", + "@babel/parser": "^7.20.5", "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -18594,11 +18593,11 @@ } }, "@babel/generator": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.3.tgz", - "integrity": "sha512-Wl5ilw2UD1+ZYprHVprxHZJCFeBWlzZYOovE4SDYLZnqCOD11j+0QzNeEWKLLTWM7nixrZEh7vNIyb76MyJg3A==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", + "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", "requires": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.20.5", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } @@ -18825,13 +18824,13 @@ } }, "@babel/helpers": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", - "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", + "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", "requires": { "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.0" + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" } }, "@babel/highlight": { @@ -18845,9 +18844,9 @@ } }, "@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==" + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -19663,26 +19662,26 @@ } }, "@babel/traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", - "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", + "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.1", + "@babel/generator": "^7.20.5", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.1", - "@babel/types": "^7.20.0", + "@babel/parser": "^7.20.5", + "@babel/types": "^7.20.5", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz", - "integrity": "sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", "requires": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index b066d3788021..865761c76c45 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -80,7 +80,7 @@ "xss": "^1.0.14" }, "devDependencies": { - "@babel/core": "^7.20.2", + "@babel/core": "^7.20.5", "@babel/preset-env": "^7.20.2", "autoprefixer": "^10.4.13", "babel-loader": "^9.1.0", From e3f9af22de69ca840acaa2aa9ed6b4d02bf4fbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Tue, 29 Nov 2022 11:53:20 +0300 Subject: [PATCH 56/66] Fix get_implementation_address_hash call --- .../lib/block_scout_web/views/api/v2/address_view.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex index 7cea8b97ec27..6d43e493e195 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex @@ -5,7 +5,7 @@ defmodule BlockScoutWeb.API.V2.AddressView do alias BlockScoutWeb.API.V2.{ApiView, Helper, TokenView} alias BlockScoutWeb.API.V2.Helper alias Explorer.{Chain, Market} - alias Explorer.Chain.Address + alias Explorer.Chain.{Address, SmartContract} alias Explorer.ExchangeRates.Token def render("message.json", assigns) do @@ -38,7 +38,7 @@ defmodule BlockScoutWeb.API.V2.AddressView do {implementation_address, implementation_name} = with true <- is_proxy, - {address, name} <- Chain.get_implementation_address_hash(address.hash, address.smart_contract.abi), + {address, name} <- SmartContract.get_implementation_address_hash(address.smart_contract), false <- is_nil(address), {:ok, address_hash} <- Chain.string_to_address_hash(address), checksummed_address <- Address.checksum(address_hash) do From 5756d9a04ab7ede3797a8461efa3bba97243995f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Tue, 29 Nov 2022 11:55:54 +0300 Subject: [PATCH 57/66] Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 501d655a9369..baae1bb3b478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ### Features -- [#5561](https://github.com/blockscout/blockscout/pull/5561) - Improve working with contracts implementations +- [#5561](https://github.com/blockscout/blockscout/pull/5561), [#6523](https://github.com/blockscout/blockscout/pull/6523) - Improve working with contracts implementations - [#6401](https://github.com/blockscout/blockscout/pull/6401) - Add Sol2Uml contract visualization - [#6481](https://github.com/blockscout/blockscout/pull/6481) - Smart contract verification improvements - [#6444](https://github.com/blockscout/blockscout/pull/6444) - Add support for yul verification via rust microservice From ae64af7dabd58c328b8626bf3e57dc7df493c8c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Tue, 29 Nov 2022 13:37:17 +0300 Subject: [PATCH 58/66] Change create to create_if_not_exists --- .../priv/repo/migrations/20221126103223_add_txs_indexes.exs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs index c7799819c045..eb439b16fb79 100644 --- a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs +++ b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs @@ -4,7 +4,7 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do @disable_migration_lock true def change do - create( + create_if_not_exists( index( :transactions, [ @@ -19,7 +19,7 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do ) ) - create( + create_if_not_exists( index( :transactions, [:to_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", "inserted_at DESC", "hash DESC"], @@ -28,7 +28,7 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do ) ) - create( + create_if_not_exists( index( :transactions, [ From 8a52fe6654feb470504289457c92bb705861832b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Tue, 29 Nov 2022 14:19:48 +0300 Subject: [PATCH 59/66] Change order for pending txs --- apps/explorer/lib/explorer/chain.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index a731bdea1642..0522e31259b5 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -3450,7 +3450,7 @@ defmodule Explorer.Chain do |> pending_transactions_query() |> apply_filter_by_method_id_to_transactions(method_id_filter) |> apply_filter_by_tx_type_to_transactions(type_filter) - |> order_by([transaction], desc: transaction.inserted_at, desc: transaction.hash) + |> order_by([transaction], desc: transaction.inserted_at, asc: transaction.hash) |> join_associations(necessity_by_association) |> (&if(old_ui?, do: preload(&1, [{:token_transfers, [:token, :from_address, :to_address]}]), else: &1)).() |> Repo.all() @@ -4396,7 +4396,7 @@ defmodule Explorer.Chain do desc: transaction.block_number, desc: transaction.index, desc: transaction.inserted_at, - desc: transaction.hash + asc: transaction.hash ) end @@ -4406,7 +4406,7 @@ defmodule Explorer.Chain do desc: transaction.block_number, desc: transaction.index, desc: transaction.inserted_at, - desc: transaction.hash + asc: transaction.hash ) end @@ -4625,7 +4625,7 @@ defmodule Explorer.Chain do [transaction], (is_nil(transaction.block_number) and (transaction.inserted_at < ^inserted_at or - (transaction.inserted_at == ^inserted_at and transaction.hash < ^hash))) or + (transaction.inserted_at == ^inserted_at and transaction.hash > ^hash))) or not is_nil(transaction.block_number) ) end From 82865bba6bf1bfb457d60c75510ef853f6f61258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Tue, 29 Nov 2022 14:27:06 +0300 Subject: [PATCH 60/66] Change indexes --- .../priv/repo/migrations/20221126103223_add_txs_indexes.exs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs index eb439b16fb79..ac0452c54eb6 100644 --- a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs +++ b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs @@ -12,7 +12,7 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", "inserted_at DESC", - "hash DESC" + "hash ASC" ], name: "transactions_from_address_hash_with_pending_index", concurrently: true @@ -22,7 +22,7 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do create_if_not_exists( index( :transactions, - [:to_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", "inserted_at DESC", "hash DESC"], + [:to_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", "inserted_at DESC", "hash ASC"], name: "transactions_to_address_hash_with_pending_index", concurrently: true ) @@ -36,7 +36,7 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", "inserted_at DESC", - "hash DESC" + "hash ASC" ], name: "transactions_created_contract_address_hash_with_pending_index", concurrently: true From 0b933447168fe8fe21abafac97283f480d3a9e89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Nov 2022 18:09:02 +0000 Subject: [PATCH 61/66] Bump mini-css-extract-plugin in /apps/block_scout_web/assets Bumps [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) from 2.7.0 to 2.7.1. - [Release notes](https://github.com/webpack-contrib/mini-css-extract-plugin/releases) - [Changelog](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v2.7.0...v2.7.1) --- updated-dependencies: - dependency-name: mini-css-extract-plugin dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 73235856dbcf..a124446ce7a1 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -83,7 +83,7 @@ "file-loader": "^6.2.0", "jest": "^29.3.1", "jest-environment-jsdom": "^29.3.1", - "mini-css-extract-plugin": "^2.7.0", + "mini-css-extract-plugin": "^2.7.1", "postcss": "^8.4.19", "postcss-loader": "^7.0.1", "sass": "^1.56.1", @@ -12922,9 +12922,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", - "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.1.tgz", + "integrity": "sha512-viOoaUFy+Z2w43VsGPbtfwFrr0tKwDctK9dUofG5MBViYhD1noGFUzzDIVw0KPwCGUP+c7zqLxm+acuQs7zLzw==", "dev": true, "dependencies": { "schema-utils": "^4.0.0" @@ -28340,9 +28340,9 @@ "peer": true }, "mini-css-extract-plugin": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", - "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.1.tgz", + "integrity": "sha512-viOoaUFy+Z2w43VsGPbtfwFrr0tKwDctK9dUofG5MBViYhD1noGFUzzDIVw0KPwCGUP+c7zqLxm+acuQs7zLzw==", "dev": true, "requires": { "schema-utils": "^4.0.0" diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index c487857bdaeb..7f6ee12e3852 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -95,7 +95,7 @@ "file-loader": "^6.2.0", "jest": "^29.3.1", "jest-environment-jsdom": "^29.3.1", - "mini-css-extract-plugin": "^2.7.0", + "mini-css-extract-plugin": "^2.7.1", "postcss": "^8.4.19", "postcss-loader": "^7.0.1", "sass": "^1.56.1", From c46e6b72b94226a1d0ccdf84bd303b283b91bcef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Nov 2022 18:09:55 +0000 Subject: [PATCH 62/66] Bump luxon from 3.1.0 to 3.1.1 in /apps/block_scout_web/assets Bumps [luxon](https://github.com/moment/luxon) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/moment/luxon/releases) - [Changelog](https://github.com/moment/luxon/blob/master/CHANGELOG.md) - [Commits](https://github.com/moment/luxon/compare/3.1.0...3.1.1) --- updated-dependencies: - dependency-name: luxon dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 73235856dbcf..06b59d955eb4 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -43,7 +43,7 @@ "lodash.omit": "^4.5.0", "lodash.rangeright": "^4.2.0", "lodash.reduce": "^4.6.0", - "luxon": "^3.1.0", + "luxon": "^3.1.1", "moment": "^2.29.4", "nanomorph": "^5.4.0", "numeral": "^2.0.6", @@ -12527,9 +12527,9 @@ "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" }, "node_modules/luxon": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.0.tgz", - "integrity": "sha512-7w6hmKC0/aoWnEsmPCu5Br54BmbmUp5GfcqBxQngRcXJ+q5fdfjEzn7dxmJh2YdDhgW8PccYtlWKSv4tQkrTQg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz", + "integrity": "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==", "engines": { "node": ">=12" } @@ -28015,9 +28015,9 @@ "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" }, "luxon": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.0.tgz", - "integrity": "sha512-7w6hmKC0/aoWnEsmPCu5Br54BmbmUp5GfcqBxQngRcXJ+q5fdfjEzn7dxmJh2YdDhgW8PccYtlWKSv4tQkrTQg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.1.1.tgz", + "integrity": "sha512-Ah6DloGmvseB/pX1cAmjbFvyU/pKuwQMQqz7d0yvuDlVYLTs2WeDHQMpC8tGjm1da+BriHROW/OEIT/KfYg6xw==" }, "make-dir": { "version": "3.1.0", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index c487857bdaeb..d1ecdcad6a82 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -55,7 +55,7 @@ "lodash.omit": "^4.5.0", "lodash.rangeright": "^4.2.0", "lodash.reduce": "^4.6.0", - "luxon": "^3.1.0", + "luxon": "^3.1.1", "moment": "^2.29.4", "nanomorph": "^5.4.0", "numeral": "^2.0.6", From d8a04f5ff66d277f3f9632c9753d413827513644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Wed, 30 Nov 2022 14:42:32 +0300 Subject: [PATCH 63/66] Fix index creation migration --- CHANGELOG.md | 1 + .../repo/migrations/20220919105140_add_method_id_index.exs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baae1bb3b478..6cd0b59f8c51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ ### Fixes +- [#6532](https://github.com/blockscout/blockscout/pull/6532) - Fix index creation migration - [#6473](https://github.com/blockscout/blockscout/pull/6473) - Fix state changes for contract creation transactions - [#6475](https://github.com/blockscout/blockscout/pull/6475) - Fix token name with unicode graphemes shortening - [#6420](https://github.com/blockscout/blockscout/pull/6420) - Fix address logs search diff --git a/apps/explorer/priv/repo/migrations/20220919105140_add_method_id_index.exs b/apps/explorer/priv/repo/migrations/20220919105140_add_method_id_index.exs index 24244fd249a7..95ad38588c15 100644 --- a/apps/explorer/priv/repo/migrations/20220919105140_add_method_id_index.exs +++ b/apps/explorer/priv/repo/migrations/20220919105140_add_method_id_index.exs @@ -5,11 +5,11 @@ defmodule Explorer.Repo.Migrations.AddMethodIdIndex do def up do execute(""" - CREATE INDEX CONCURRENTLY method_id ON public.transactions USING btree (substring(input for 4)); + CREATE INDEX CONCURRENTLY IF NOT EXISTS method_id ON public.transactions USING btree (substring(input for 4)); """) end def down do - execute("DROP INDEX method_id") + execute("DROP INDEX IF EXISTS method_id") end end From 2dc277ebf08affcf1166dc5affe934bbc2d77dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=9F=D0=BE=D0=B7?= =?UTF-8?q?=D0=B4=D0=BD=D1=8F=D0=BA=D0=BE=D0=B2?= Date: Tue, 29 Nov 2022 14:54:49 +0300 Subject: [PATCH 64/66] Cast pagination on address to one order_by set --- apps/explorer/lib/explorer/chain.ex | 16 +++-------- .../20221126103223_add_txs_indexes.exs | 27 +++++++++++++++++++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 0522e31259b5..5713f5b531cd 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -4385,12 +4385,12 @@ defmodule Explorer.Chain do defp fetch_transactions(paging_options \\ nil, from_block \\ nil, to_block \\ nil, is_address? \\ false) do Transaction - |> order_for_transactions(paging_options, is_address?) + |> order_for_transactions(is_address?) |> where_block_number_in_period(from_block, to_block) |> handle_paging_options(paging_options) end - defp order_for_transactions(query, %PagingOptions{is_pending_tx: true}, true) do + defp order_for_transactions(query, true) do query |> order_by([transaction], desc: transaction.block_number, @@ -4400,17 +4400,7 @@ defmodule Explorer.Chain do ) end - defp order_for_transactions(query, %PagingOptions{key: nil}, true) do - query - |> order_by([transaction], - desc: transaction.block_number, - desc: transaction.index, - desc: transaction.inserted_at, - asc: transaction.hash - ) - end - - defp order_for_transactions(query, _, _) do + defp order_for_transactions(query, _) do query |> order_by([transaction], desc: transaction.block_number, desc: transaction.index) end diff --git a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs index ac0452c54eb6..241ed059688c 100644 --- a/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs +++ b/apps/explorer/priv/repo/migrations/20221126103223_add_txs_indexes.exs @@ -4,6 +4,33 @@ defmodule Explorer.Repo.Migrations.AddTxsIndexes do @disable_migration_lock true def change do + drop_if_exists( + index( + :transactions, + [:from_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", :hash], + name: "transactions_from_address_hash_recent_collated_index", + concurrently: true + ) + ) + + drop_if_exists( + index( + :transactions, + [:to_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", :hash], + name: "transactions_to_address_hash_recent_collated_index", + concurrently: true + ) + ) + + drop_if_exists( + index( + :transactions, + [:created_contract_address_hash, "block_number DESC NULLS FIRST", "index DESC NULLS FIRST", :hash], + name: "transactions_created_contract_address_hash_recent_collated_index", + concurrently: true + ) + ) + create_if_not_exists( index( :transactions, From 11c683f8c647ee1dc9d63e930d79dd05c8ca58ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:10:54 +0000 Subject: [PATCH 65/66] Bump postcss-loader from 7.0.1 to 7.0.2 in /apps/block_scout_web/assets Bumps [postcss-loader](https://github.com/webpack-contrib/postcss-loader) from 7.0.1 to 7.0.2. - [Release notes](https://github.com/webpack-contrib/postcss-loader/releases) - [Changelog](https://github.com/webpack-contrib/postcss-loader/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/postcss-loader/compare/v7.0.1...v7.0.2) --- updated-dependencies: - dependency-name: postcss-loader dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 30 +++++++++---------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 003fedec8883..6d37ab461298 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -85,7 +85,7 @@ "jest-environment-jsdom": "^29.3.1", "mini-css-extract-plugin": "^2.7.1", "postcss": "^8.4.19", - "postcss-loader": "^7.0.1", + "postcss-loader": "^7.0.2", "sass": "^1.56.1", "sass-loader": "^13.2.0", "style-loader": "^3.3.1", @@ -14211,14 +14211,14 @@ } }, "node_modules/postcss-loader": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", - "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", "dev": true, "dependencies": { "cosmiconfig": "^7.0.0", "klona": "^2.0.5", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "engines": { "node": ">= 14.15.0" @@ -14233,9 +14233,9 @@ } }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -29304,20 +29304,20 @@ "requires": {} }, "postcss-loader": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", - "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", "dev": true, "requires": { "cosmiconfig": "^7.0.0", "klona": "^2.0.5", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "dependencies": { "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 6169de664243..8bf89bbad101 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -97,7 +97,7 @@ "jest-environment-jsdom": "^29.3.1", "mini-css-extract-plugin": "^2.7.1", "postcss": "^8.4.19", - "postcss-loader": "^7.0.1", + "postcss-loader": "^7.0.2", "sass": "^1.56.1", "sass-loader": "^13.2.0", "style-loader": "^3.3.1", From 0a0cca07f47e7a8180d0d6d16d6ed2eb1398c2ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Nov 2022 18:11:38 +0000 Subject: [PATCH 66/66] Bump sweetalert2 from 11.6.14 to 11.6.15 in /apps/block_scout_web/assets Bumps [sweetalert2](https://github.com/sweetalert2/sweetalert2) from 11.6.14 to 11.6.15. - [Release notes](https://github.com/sweetalert2/sweetalert2/releases) - [Changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md) - [Commits](https://github.com/sweetalert2/sweetalert2/compare/v11.6.14...v11.6.15) --- updated-dependencies: - dependency-name: sweetalert2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- apps/block_scout_web/assets/package-lock.json | 14 +++++++------- apps/block_scout_web/assets/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json index 003fedec8883..0459d3f0194a 100644 --- a/apps/block_scout_web/assets/package-lock.json +++ b/apps/block_scout_web/assets/package-lock.json @@ -58,7 +58,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.14", + "sweetalert2": "^11.6.15", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5", @@ -16811,9 +16811,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/sweetalert2": { - "version": "11.6.14", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.14.tgz", - "integrity": "sha512-W8+vtsucIJg5BrFhHcqguNZMzmHGvVZVAYHaMGQ9dzrleOMZcHCGmnB46L9qUNdx5snr1GpMUVFjNuki7EBbuQ==", + "version": "11.6.15", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.15.tgz", + "integrity": "sha512-FqMy1gRGHEI5G145NE5XSP059TziCJu9Xf9/mkki/aKu5pLNcYzjggOzKO5Ex10EBgAGDXQ99jyGfYYzGCYXRQ==", "funding": { "type": "individual", "url": "https://github.com/sponsors/limonte" @@ -31236,9 +31236,9 @@ } }, "sweetalert2": { - "version": "11.6.14", - "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.14.tgz", - "integrity": "sha512-W8+vtsucIJg5BrFhHcqguNZMzmHGvVZVAYHaMGQ9dzrleOMZcHCGmnB46L9qUNdx5snr1GpMUVFjNuki7EBbuQ==" + "version": "11.6.15", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.6.15.tgz", + "integrity": "sha512-FqMy1gRGHEI5G145NE5XSP059TziCJu9Xf9/mkki/aKu5pLNcYzjggOzKO5Ex10EBgAGDXQ99jyGfYYzGCYXRQ==" }, "symbol-tree": { "version": "3.2.4", diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json index 6169de664243..50a73c14360b 100644 --- a/apps/block_scout_web/assets/package.json +++ b/apps/block_scout_web/assets/package.json @@ -70,7 +70,7 @@ "redux": "^4.2.0", "stream-browserify": "^3.0.0", "stream-http": "^3.1.1", - "sweetalert2": "^11.6.14", + "sweetalert2": "^11.6.15", "urijs": "^1.19.11", "url": "^0.11.0", "util": "^0.12.5",