chore: move `has_methods_*` fields to `/smart-contracts` endpoint response (#9599)

* chore: move `methods`-related fields to `/api/v2/smart-contracts/{address_hash}` endpoint response`

* fix: add custom abi predicate fields to unverified contract response

* refactor: do not put not necessary `conn`

* chore: add RPC-call expectations in tests
pull/9884/head
Fedor Ivanov 7 months ago committed by GitHub
parent cc505f72ca
commit 5755e46b2f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 29
      apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex
  2. 165
      apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs

@ -22,8 +22,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do
%{"items" => Enum.map(smart_contracts, &prepare_smart_contract_for_list/1), "next_page_params" => next_page_params}
end
def render("smart_contract.json", %{address: address}) do
prepare_smart_contract(address)
def render("smart_contract.json", %{address: address, conn: conn}) do
prepare_smart_contract(address, conn)
end
def render("read_functions.json", %{functions: functions}) do
@ -146,12 +146,18 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do
defp prepare_output(output), do: output
# credo:disable-for-next-line
def prepare_smart_contract(%Address{smart_contract: %SmartContract{} = smart_contract} = address) do
def prepare_smart_contract(%Address{smart_contract: %SmartContract{} = smart_contract} = address, conn) do
minimal_proxy_template = EIP1167.get_implementation_address(address.hash, @api_true)
bytecode_twin = SmartContract.get_address_verified_twin_contract(address.hash, @api_true)
metadata_for_verification = minimal_proxy_template || bytecode_twin.verified_contract
smart_contract_verified = AddressView.smart_contract_verified?(address)
fully_verified = SmartContract.verified_with_full_match?(address.hash, @api_true)
write_methods? = AddressView.smart_contract_with_write_functions?(address)
is_proxy = AddressView.smart_contract_is_proxy?(address, @api_true)
read_custom_abi? = AddressView.has_address_custom_abi_with_read_functions?(conn, address.hash)
write_custom_abi? = AddressView.has_address_custom_abi_with_write_functions?(conn, address.hash)
additional_sources =
additional_sources(smart_contract, smart_contract_verified, minimal_proxy_template, bytecode_twin)
@ -170,6 +176,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do
"is_verified_via_eth_bytecode_db" => address.smart_contract.verified_via_eth_bytecode_db,
"is_verified_via_verifier_alliance" => address.smart_contract.verified_via_verifier_alliance,
"is_vyper_contract" => target_contract.is_vyper_contract,
"has_custom_methods_read" => read_custom_abi?,
"has_custom_methods_write" => write_custom_abi?,
"has_methods_read" => AddressView.smart_contract_with_read_only_functions?(address),
"has_methods_write" => write_methods?,
"has_methods_read_proxy" => is_proxy,
"has_methods_write_proxy" => is_proxy && write_methods?,
"minimal_proxy_address_hash" =>
minimal_proxy_template && Address.checksum(metadata_for_verification.address_hash),
"sourcify_repo_url" =>
@ -201,8 +213,15 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do
|> Map.merge(bytecode_info(address))
end
def prepare_smart_contract(address) do
bytecode_info(address)
def prepare_smart_contract(address, conn) do
read_custom_abi? = AddressView.has_address_custom_abi_with_read_functions?(conn, address.hash)
write_custom_abi? = AddressView.has_address_custom_abi_with_write_functions?(conn, address.hash)
%{
"has_custom_methods_read" => read_custom_abi?,
"has_custom_methods_write" => write_custom_abi?
}
|> Map.merge(bytecode_info(address))
end
@doc """

@ -36,6 +36,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" => nil
@ -53,6 +55,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -86,6 +90,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"is_fully_verified" => true,
"is_verified_via_sourcify" => target_contract.verified_via_sourcify,
"is_vyper_contract" => target_contract.is_vyper_contract,
"has_methods_read" => true,
"has_methods_write" => true,
"has_methods_read_proxy" => true,
"has_methods_write_proxy" => true,
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"minimal_proxy_address_hash" => nil,
"sourcify_repo_url" =>
if(target_contract.verified_via_sourcify,
@ -117,6 +127,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"license_type" => "none"
}
get_eip1967_implementation_non_zero_address()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(target_contract.address_hash)}")
response = json_response(request, 200)
@ -177,6 +189,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"is_fully_verified" => true,
"is_verified_via_sourcify" => target_contract.verified_via_sourcify,
"is_vyper_contract" => target_contract.is_vyper_contract,
"has_methods_read" => true,
"has_methods_read_proxy" => false,
"has_methods_write" => true,
"has_methods_write_proxy" => false,
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"minimal_proxy_address_hash" => nil,
"sourcify_repo_url" =>
if(target_contract.verified_via_sourcify,
@ -211,6 +229,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"license_type" => "gnu_agpl_v3"
}
get_eip1967_implementation_error_response()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(target_contract.address_hash)}")
response = json_response(request, 200)
@ -279,6 +299,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"is_fully_verified" => false,
"is_verified_via_sourcify" => false,
"is_vyper_contract" => target_contract.is_vyper_contract,
"has_methods_read" => true,
"has_methods_write" => true,
"has_methods_read_proxy" => false,
"has_methods_write_proxy" => false,
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"minimal_proxy_address_hash" => nil,
"sourcify_repo_url" => nil,
"can_be_visualized_via_sol2uml" => false,
@ -307,6 +333,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"license_type" => "none"
}
get_eip1967_implementation_error_response()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
response = json_response(request, 200)
@ -390,6 +418,12 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"is_fully_verified" => false,
"is_verified_via_sourcify" => false,
"is_vyper_contract" => implementation_contract.is_vyper_contract,
"has_methods_read" => true,
"has_methods_write" => true,
"has_methods_read_proxy" => true,
"has_methods_write_proxy" => true,
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"minimal_proxy_address_hash" => Address.checksum("0x" <> implementation_contract_address_hash_string),
"sourcify_repo_url" => nil,
"can_be_visualized_via_sol2uml" => false,
@ -475,6 +509,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Conn.resp(conn, 200, eth_bytecode_response)
end)
get_eip1967_implementation_error_response()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
@ -495,6 +531,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -554,6 +592,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Conn.resp(conn, 200, eth_bytecode_response)
end)
get_eip1967_implementation_error_response()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
@ -574,6 +614,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -700,12 +742,16 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582061b7676067d537e410bb704932a9984739a959416170ea17bda192ac1218d2790029"
}
get_eip1967_implementation_error_response()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert response = json_response(request, 200)
assert %{"is_verified" => true} = response
@ -763,6 +809,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Conn.resp(conn, 200, eth_bytecode_response)
end)
get_eip1967_implementation_error_response()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
@ -783,6 +831,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -869,6 +919,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Conn.resp(conn, 200, eth_bytecode_response)
end)
get_eip1967_implementation_non_zero_address()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
@ -889,6 +941,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -980,6 +1034,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Conn.resp(conn, 200, eth_bytecode_response)
end)
get_eip1967_implementation_non_zero_address()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
@ -1000,6 +1056,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -1091,6 +1149,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
Conn.resp(conn, 200, eth_bytecode_response)
end)
get_eip1967_implementation_non_zero_address()
request = get(conn, "/api/v2/smart-contracts/#{Address.checksum(address.hash)}")
assert_receive %Phoenix.Socket.Message{
@ -1111,6 +1171,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert response ==
%{
"has_custom_methods_read" => false,
"has_custom_methods_write" => false,
"is_self_destructed" => false,
"deployed_bytecode" => to_string(address.contract_code),
"creation_bytecode" =>
@ -3219,4 +3281,107 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
{:ok, "0x000000000000000000000000#{address_hash |> to_string() |> String.replace("0x", "")}"}
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, "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, "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)
|> mock_empty_beacon_storage_pointer_request()
|> mock_empty_oz_storage_pointer_request()
|> mock_empty_eip_1822_storage_pointer_request()
end
defp mock_empty_beacon_storage_pointer_request(mox) do
expect(mox, :json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",
params: [
_,
"0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50",
"latest"
]
},
_options ->
{:ok, "0x0000000000000000000000000000000000000000000000000000000000000000"}
end)
end
defp mock_empty_eip_1822_storage_pointer_request(mox) do
expect(mox, :json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",
params: [
_,
"0xc5f16f0fcc639fa48a6947836d9850f504798523bf8c9a3a87d5876cf622bcf7",
"latest"
]
},
_options ->
{:ok, "0x0000000000000000000000000000000000000000000000000000000000000000"}
end)
end
defp mock_empty_oz_storage_pointer_request(mox) do
expect(mox, :json_rpc, fn %{
id: 0,
method: "eth_getStorageAt",
params: [
_,
"0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3",
"latest"
]
},
_options ->
{:ok, "0x0000000000000000000000000000000000000000000000000000000000000000"}
end)
end
end

Loading…
Cancel
Save