From 348a8acc1e5fd9359d7ee0d12937cc22c729e2c6 Mon Sep 17 00:00:00 2001 From: Nikita Pozdniakov Date: Mon, 17 Jul 2023 22:31:37 +0700 Subject: [PATCH] Add parsing constructor arguments for sourcify contracts --- apps/explorer/lib/explorer/chain.ex | 34 +++++++++++++++++-- .../smart_contract/solidity/verifier.ex | 34 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index dd4200d0f0..e2ed916029 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -98,6 +98,7 @@ defmodule Explorer.Chain do alias Explorer.Market.MarketHistoryCache alias Explorer.{PagingOptions, Repo} alias Explorer.SmartContract.Helper + alias Explorer.SmartContract.Solidity.Verifier alias Explorer.Tags.{AddressTag, AddressToTag} alias Dataloader.Ecto, as: DataloaderEcto @@ -1913,7 +1914,7 @@ defmodule Explorer.Chain do if smart_contract do CheckBytecodeMatchingOnDemand.trigger_check(address_result, smart_contract) LookUpSmartContractSourcesOnDemand.trigger_fetch(address_result, smart_contract) - address_result + check_and_update_constructor_args(address_result) else LookUpSmartContractSourcesOnDemand.trigger_fetch(address_result, nil) @@ -1936,6 +1937,35 @@ defmodule Explorer.Chain do end end + defp check_and_update_constructor_args( + %SmartContract{address_hash: address_hash, constructor_arguments: nil} = smart_contract + ) do + if args = Verifier.parse_constructor_arguments_for_sourcify_contract(address_hash, smart_contract.abi) do + smart_contract |> SmartContract.changeset(%{constructor_arguments: args}) |> Repo.update() + %SmartContract{smart_contract | constructor_arguments: args} + else + smart_contract + end + end + + defp check_and_update_constructor_args( + %Address{ + hash: address_hash, + contract_code: deployed_bytecode, + smart_contract: %SmartContract{constructor_arguments: nil} = smart_contract + } = address + ) do + if args = + Verifier.parse_constructor_arguments_for_sourcify_contract(address_hash, smart_contract.abi, deployed_bytecode) do + smart_contract |> SmartContract.changeset(%{constructor_arguments: args}) |> Repo.update() + %Address{address | smart_contract: %SmartContract{smart_contract | constructor_arguments: args}} + else + address + end + end + + defp check_and_update_constructor_args(other), do: other + defp add_twin_info_to_contract(address_result, address_verified_twin_contract, _hash) when is_nil(address_verified_twin_contract), do: address_result @@ -4310,7 +4340,7 @@ defmodule Explorer.Chain do verified_contract_twin_additional_sources = get_contract_additional_sources(verified_contract_twin, options) %{ - :verified_contract => verified_contract_twin, + :verified_contract => check_and_update_constructor_args(verified_contract_twin), :additional_sources => verified_contract_twin_additional_sources } else diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex index 57c11709ab..50cd34a24d 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex @@ -13,6 +13,7 @@ defmodule Explorer.SmartContract.Solidity.Verifier do alias ABI.{FunctionSelector, TypeDecoder} alias Explorer.Chain + alias Explorer.Chain.Data alias Explorer.SmartContract.RustVerifierInterface alias Explorer.SmartContract.Solidity.CodeCompiler @@ -533,4 +534,37 @@ defmodule Explorer.SmartContract.Solidity.Verifier do def parse_boolean(false), do: false def parse_boolean(_), do: false + + def parse_constructor_arguments_for_sourcify_contract(address_hash, abi) do + parse_constructor_arguments_for_sourcify_contract(address_hash, abi, Chain.smart_contract_bytecode(address_hash)) + end + + def parse_constructor_arguments_for_sourcify_contract(address_hash, abi, deployed_bytecode) + when is_binary(deployed_bytecode) do + creation_tx_input = + case Chain.smart_contract_creation_tx_bytecode(address_hash) do + %{init: init, created_contract_code: _created_contract_code} -> + "0x" <> init_without_0x = init + init_without_0x + + _ -> + nil + end + + with true <- has_constructor_with_params?(abi), + check_function <- parse_constructor_and_return_check_function(abi), + false <- is_nil(creation_tx_input) || deployed_bytecode == "0x", + {meta, meta_length} <- extract_meta_from_deployed_bytecode(deployed_bytecode), + [_bytecode, constructor_args] <- String.split(creation_tx_input, meta <> meta_length), + ^constructor_args <- check_function.(constructor_args) do + constructor_args + else + _ -> + nil + end + end + + def parse_constructor_arguments_for_sourcify_contract(address_hash, abi, deployed_bytecode) do + parse_constructor_arguments_for_sourcify_contract(address_hash, abi, Data.to_string(deployed_bytecode)) + end end