|
|
|
@ -12,9 +12,15 @@ defmodule BlockScoutWeb.API.V2.AddressController do |
|
|
|
|
import BlockScoutWeb.PagingHelper, |
|
|
|
|
only: [delete_parameters_from_next_page_params: 1, token_transfers_types_options: 1] |
|
|
|
|
|
|
|
|
|
import Explorer.SmartContract.Solidity.Verifier, only: [parse_boolean: 1] |
|
|
|
|
|
|
|
|
|
alias BlockScoutWeb.AccessHelpers |
|
|
|
|
alias BlockScoutWeb.API.V2.{AddressView, BlockView, TransactionView} |
|
|
|
|
alias BlockScoutWeb.AddressContractVerificationController, as: VerificationController |
|
|
|
|
alias BlockScoutWeb.AddressView |
|
|
|
|
alias BlockScoutWeb.API.V2.{BlockView, TransactionView} |
|
|
|
|
alias Explorer.{Chain, Market} |
|
|
|
|
alias Explorer.Chain.SmartContract |
|
|
|
|
alias Explorer.SmartContract.{Reader, Writer} |
|
|
|
|
alias Indexer.Fetcher.TokenBalanceOnDemand |
|
|
|
|
|
|
|
|
|
@transaction_necessity_by_association [ |
|
|
|
@ -37,6 +43,14 @@ defmodule BlockScoutWeb.API.V2.AddressController do |
|
|
|
|
} |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
@smart_contract_address_options [ |
|
|
|
|
necessity_by_association: %{ |
|
|
|
|
:smart_contract => :optional |
|
|
|
|
} |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
@burn_address "0x0000000000000000000000000000000000000000" |
|
|
|
|
|
|
|
|
|
action_fallback(BlockScoutWeb.API.V2.FallbackController) |
|
|
|
|
|
|
|
|
|
def address(conn, %{"address_hash" => address_hash_string} = params) do |
|
|
|
@ -249,7 +263,6 @@ defmodule BlockScoutWeb.API.V2.AddressController do |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> put_view(AddressView) |
|
|
|
|
|> render(:coin_balances, %{coin_balances: coin_balances, next_page_params: next_page_params}) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
@ -263,8 +276,139 @@ defmodule BlockScoutWeb.API.V2.AddressController do |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> put_view(AddressView) |
|
|
|
|
|> render(:coin_balances_by_day, %{coin_balances_by_day: balances_by_day}) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def smart_contract(conn, %{"address_hash" => address_hash_string} = params) do |
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params), |
|
|
|
|
_ <- VerificationController.check_and_verify(address_hash_string), |
|
|
|
|
{:not_found, {:ok, address}} <- |
|
|
|
|
{:not_found, Chain.find_contract_address(address_hash, @smart_contract_address_options, true)} do |
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> render(:smart_contract, %{address: address}) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def methods_read(conn, %{"address_hash" => address_hash_string, "is_custom_abi" => "true"} = params) do |
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params), |
|
|
|
|
custom_abi <- AddressView.fetch_custom_abi(conn, address_hash_string), |
|
|
|
|
{:not_found, true} <- {:not_found, AddressView.check_custom_abi_for_having_read_functions(custom_abi)} do |
|
|
|
|
read_only_functions_from_abi = |
|
|
|
|
Reader.read_only_functions_from_abi_with_sender(custom_abi.abi, address_hash, params["from"]) |
|
|
|
|
|
|
|
|
|
read_functions_required_wallet_from_abi = Reader.read_functions_required_wallet_from_abi(custom_abi.abi) |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(read_only_functions_from_abi ++ read_functions_required_wallet_from_abi) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def methods_read(conn, %{"address_hash" => address_hash_string} = params) do |
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params) do |
|
|
|
|
read_only_functions_from_abi = Reader.read_only_functions(address_hash, params["from"]) |> debug("r only") |
|
|
|
|
|
|
|
|
|
read_functions_required_wallet_from_abi = |
|
|
|
|
Reader.read_functions_required_wallet(address_hash) |> debug("r req wall") |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(read_only_functions_from_abi ++ read_functions_required_wallet_from_abi) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def methods_write(conn, %{"address_hash" => address_hash_string, "is_custom_abi" => "true"} = params) do |
|
|
|
|
with {:format, {:ok, _address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params), |
|
|
|
|
custom_abi <- AddressView.fetch_custom_abi(conn, address_hash_string), |
|
|
|
|
{:not_found, true} <- {:not_found, AddressView.check_custom_abi_for_having_read_functions(custom_abi)} do |
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(Writer.filter_write_functions(custom_abi.abi)) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def methods_write(conn, %{"address_hash" => address_hash_string} = params) do |
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params) do |
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(Writer.write_functions(address_hash)) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def methods_read_proxy(conn, %{"address_hash" => address_hash_string} = params) do |
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params), |
|
|
|
|
{:not_found, {:ok, address}} <- |
|
|
|
|
{:not_found, Chain.find_contract_address(address_hash, @smart_contract_address_options)} do |
|
|
|
|
implementation_address_hash_string = |
|
|
|
|
address.smart_contract |
|
|
|
|
|> SmartContract.get_implementation_address_hash() |
|
|
|
|
|> Tuple.to_list() |
|
|
|
|
|> List.first() || @burn_address |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(Reader.read_only_functions_proxy(address_hash, implementation_address_hash_string, params["from"])) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def methods_write_proxy(conn, %{"address_hash" => address_hash_string} = params) do |
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params), |
|
|
|
|
{:not_found, {:ok, address}} <- |
|
|
|
|
{:not_found, Chain.find_contract_address(address_hash, @smart_contract_address_options)} do |
|
|
|
|
implementation_address_hash_string = |
|
|
|
|
address.smart_contract |
|
|
|
|
|> SmartContract.get_implementation_address_hash() |
|
|
|
|
|> Tuple.to_list() |
|
|
|
|
|> List.first() || @burn_address |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(Writer.write_functions_proxy(implementation_address_hash_string)) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def query_read_method( |
|
|
|
|
conn, |
|
|
|
|
%{"address_hash" => address_hash_string, "is_custom_abi" => custom_abi, "contract_type" => type, "args" => args} = |
|
|
|
|
params |
|
|
|
|
) do |
|
|
|
|
custom_abi = |
|
|
|
|
if parse_boolean(params["is_custom_abi"]), do: AddressView.fetch_custom_abi(conn, params["id"]), else: nil |
|
|
|
|
|
|
|
|
|
contract_type = if type == "proxy", do: :proxy, else: :regular |
|
|
|
|
|
|
|
|
|
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)}, |
|
|
|
|
{:ok, false} <- AccessHelpers.restricted_access?(address_hash_string, params), |
|
|
|
|
{:not_found, {:ok, _address}} <- {:not_found, Chain.find_contract_address(address_hash, [])} do |
|
|
|
|
%{output: outputs, names: _names} = |
|
|
|
|
if custom_abi do |
|
|
|
|
Reader.query_function_with_names_custom_abi( |
|
|
|
|
address_hash, |
|
|
|
|
%{method_id: params["method_id"], args: args}, |
|
|
|
|
params["from"], |
|
|
|
|
custom_abi.abi |
|
|
|
|
) |
|
|
|
|
else |
|
|
|
|
Reader.query_function_with_names( |
|
|
|
|
address_hash, |
|
|
|
|
%{method_id: params["method_id"], args: args}, |
|
|
|
|
contract_type, |
|
|
|
|
params["from"] |
|
|
|
|
) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
conn |
|
|
|
|
|> put_status(200) |
|
|
|
|
|> json(outputs) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|