From b5bce41ab9ef5c9d8589e8f12be9777f5245d221 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Thu, 14 Nov 2019 13:07:30 +0300 Subject: [PATCH 1/8] Extend getsourcecode API view with new output fields --- CHANGELOG.md | 1 + .../views/api/rpc/contract_view.ex | 96 +++++++++++++++---- .../api/rpc/contract_controller_test.exs | 65 +++++-------- 3 files changed, 101 insertions(+), 61 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 946fcd1e45..2ca108a165 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Current ### Features +- [#2857](https://github.com/poanetwork/blockscout/pull/2857) - Extend getsourcecode API view with new output fields - [#2787](https://github.com/poanetwork/blockscout/pull/2787) - async fetching of address counters - [#2791](https://github.com/poanetwork/blockscout/pull/2791) - add ipc client - [#2449](https://github.com/poanetwork/blockscout/pull/2449) - add ability to send notification events through postgres notify 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 8f996a2bcc..0d0557469b 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 @@ -35,7 +35,11 @@ defmodule BlockScoutWeb.API.RPC.ContractView do "CompilerVersion" => "", "DecompiledSourceCode" => "", "DecompilerVersion" => decompiler_version(nil), - "OptimizationUsed" => "" + "OptimizationUsed" => "", + "OptimizationRuns" => "", + "EVMVersion" => "", + "ConstructorArguments" => "", + "ExternalLibraries" => "" } end @@ -43,6 +47,64 @@ defmodule BlockScoutWeb.API.RPC.ContractView do decompiled_smart_contract = latest_decompiled_smart_contract(address.decompiled_smart_contracts) contract = address.smart_contract || %{} + optimization = Map.get(contract, :optimization, "") + + contract_output = %{ + "Address" => to_string(address.hash) + } + + contract_output + |> set_decompiled_contract_data(decompiled_smart_contract) + |> set_optimization_runs(contract, optimization) + |> set_constructor_arguments(contract) + |> set_external_libraries(contract) + |> set_verified_contract_data(contract, address, optimization) + end + + defp set_decompiled_contract_data(contract_output, decompiled_smart_contract) do + if decompiled_smart_contract do + contract_output + |> Map.put_new(:DecompiledSourceCode, decompiled_source_code(decompiled_smart_contract)) + |> Map.put_new(:DecompilerVersion, decompiler_version(decompiled_smart_contract)) + else + contract_output + end + end + + defp set_optimization_runs(contract_output, contract, optimization) do + optimization_runs = Map.get(contract, :optimization_runs, "") + + if optimization && optimization != "" do + contract_output + |> Map.put_new(:OptimizationRuns, optimization_runs) + else + contract_output + end + end + + defp set_constructor_arguments(contract_output, contract) do + constructor_arguments = Map.get(contract, :constructor_arguments, "") + + if constructor_arguments && constructor_arguments != "" do + contract_output + |> Map.put_new(:ConstructorArguments, constructor_arguments) + else + contract_output + end + end + + defp set_external_libraries(contract_output, contract) do + external_libraries = Map.get(contract, :external_libraries, []) + + if Enum.count(external_libraries) > 0 do + contract_output + |> Map.put_new(:ExternalLibraries, external_libraries) + else + contract_output + end + end + + defp set_verified_contract_data(contract_output, contract, address, optimization) do contract_abi = if is_nil(address.smart_contract) do "Contract source code not verified" @@ -51,27 +113,28 @@ defmodule BlockScoutWeb.API.RPC.ContractView do end contract_optimization = - case Map.get(contract, :optimization, "") do + case optimization do true -> - "1" + "true" false -> - "0" + "false" "" -> "" end - %{ - "Address" => to_string(address.hash), - "SourceCode" => Map.get(contract, :contract_source_code, ""), - "ABI" => contract_abi, - "ContractName" => Map.get(contract, :name, ""), - "DecompiledSourceCode" => decompiled_source_code(decompiled_smart_contract), - "DecompilerVersion" => decompiler_version(decompiled_smart_contract), - "CompilerVersion" => Map.get(contract, :compiler_version, ""), - "OptimizationUsed" => contract_optimization - } + if Map.equal?(contract, %{}) do + contract_output + else + contract_output + |> Map.put_new(:SourceCode, Map.get(contract, :contract_source_code, "")) + |> Map.put_new(:ABI, contract_abi) + |> Map.put_new(:ContractName, Map.get(contract, :name, "")) + |> Map.put_new(:CompilerVersion, Map.get(contract, :compiler_version, "")) + |> Map.put_new(:OptimizationUsed, contract_optimization) + |> Map.put_new(:EVMVersion, Map.get(contract, :evm_version, "")) + end end defp prepare_contract(%Address{ @@ -80,10 +143,7 @@ defmodule BlockScoutWeb.API.RPC.ContractView do }) do %{ "Address" => to_string(hash), - "ABI" => "Contract source code not verified", - "ContractName" => "", - "CompilerVersion" => "", - "OptimizationUsed" => "" + "ABI" => "Contract source code not verified" } end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs index 37ce57f508..f4af65e9ac 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs @@ -70,10 +70,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(address.hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(address.hash) } ] @@ -95,10 +92,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(address.hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(address.hash) } ] @@ -124,10 +118,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(address.hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(address.hash) } ] @@ -174,10 +165,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(decompiled_smart_contract.address_hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(decompiled_smart_contract.address_hash) } ] @@ -199,10 +187,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(smart_contract.address_hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(smart_contract.address_hash) } ] @@ -225,10 +210,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert %{ "ABI" => "Contract source code not verified", - "Address" => to_string(smart_contract.address_hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(smart_contract.address_hash) } in response["result"] refute to_string(non_match.address_hash) in Enum.map(response["result"], &Map.get(&1, "Address")) @@ -251,10 +233,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(contract_address.hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(contract_address.hash) } ] @@ -281,10 +260,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["result"] == [ %{ "ABI" => "Contract source code not verified", - "Address" => to_string(contract_address.hash), - "CompilerVersion" => "", - "ContractName" => "", - "OptimizationUsed" => "" + "Address" => to_string(contract_address.hash) } ] @@ -423,7 +399,11 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do "CompilerVersion" => "", "OptimizationUsed" => "", "DecompiledSourceCode" => "", - "DecompilerVersion" => "" + "DecompilerVersion" => "", + "ConstructorArguments" => "", + "EVMVersion" => "", + "ExternalLibraries" => "", + "OptimizationRuns" => "" } ] @@ -439,7 +419,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do end test "with a verified contract address", %{conn: conn} do - contract = insert(:smart_contract, optimization: true) + contract = insert(:smart_contract, optimization: true, optimization_runs: 200, evm_version: "default") params = %{ "module" => "contract", @@ -456,12 +436,12 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do "ABI" => Jason.encode!(contract.abi), "ContractName" => contract.name, "CompilerVersion" => contract.compiler_version, - "DecompiledSourceCode" => "Contract source code not decompiled.", # The contract's optimization value is true, so the expected value # for `OptimizationUsed` is "1". If it was false, the expected value # would be "0". - "DecompilerVersion" => "", - "OptimizationUsed" => "1" + "OptimizationUsed" => "true", + "OptimizationRuns" => 200, + "EVMVersion" => "default" } ] @@ -508,9 +488,8 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do "ABI" => Jason.encode!(contract_code_info.abi), "ContractName" => contract_code_info.name, "CompilerVersion" => contract_code_info.version, - "DecompiledSourceCode" => "Contract source code not decompiled.", - "DecompilerVersion" => "", - "OptimizationUsed" => "0" + "OptimizationUsed" => "false", + "EVMVersion" => nil } assert response["status"] == "1" @@ -578,9 +557,9 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do contract_source_code assert result["ContractName"] == name - assert result["DecompiledSourceCode"] == "Contract source code not decompiled." - assert result["DecompilerVersion"] == "" - assert result["OptimizationUsed"] == "1" + assert result["DecompiledSourceCode"] == nil + assert result["DecompilerVersion"] == nil + assert result["OptimizationUsed"] == "true" assert :ok = ExJsonSchema.Validator.validate(verify_schema(), response) end end From 56f07bb85eaf54c16bf3ddc5a1144a3538d09cd0 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Fri, 29 Nov 2019 16:10:18 +0300 Subject: [PATCH 2/8] check fetched metadata in multiple places --- .../token/instance_metadata_retriever.ex | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex b/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex index bdddfde482..bde63ee1e9 100644 --- a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex +++ b/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex @@ -80,7 +80,7 @@ defmodule Explorer.Token.InstanceMetadataRetriever do def fetch_json(%{"tokenURI" => {:ok, [json]}}) do {:ok, json} = decode_json(json) - {:ok, %{metadata: json}} + check_type(json) rescue e -> Logger.debug(["Unknown metadata format #{inspect(json)}. error #{inspect(e)}"], @@ -101,11 +101,7 @@ defmodule Explorer.Token.InstanceMetadataRetriever do {:ok, %Response{body: body, status_code: 200}} -> {:ok, json} = decode_json(body) - if is_map(json) do - {:ok, %{metadata: json}} - else - {:error, :wrong_metadata_type} - end + check_type(json) {:ok, %Response{body: body}} -> {:error, body} @@ -131,4 +127,12 @@ defmodule Explorer.Token.InstanceMetadataRetriever do |> Jason.decode() end end + + defp check_type(json) when is_map(json) do + {:ok, %{metadata: json}} + end + + defp check_type(_) do + {:error, :wrong_metadata_type} + end end From 36516a04dd10bc45967074beaebf9288cea2e603 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Fri, 29 Nov 2019 16:14:01 +0300 Subject: [PATCH 3/8] add CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62ce88bd8d..89d6bada39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Fixes +- [#2900](https://github.com/poanetwork/blockscout/pull/2900) - check fetched instance metadata in multiple places + ### Chore - [#2896](https://github.com/poanetwork/blockscout/pull/2896) - Disable Parity websockets tests From bde993f75dd01ab9f5e71bffadda8d2959e4e39b Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Tue, 10 Dec 2019 15:52:10 +0300 Subject: [PATCH 4/8] Add additional tests --- .../views/api/rpc/contract_view.ex | 7 +- .../api/rpc/contract_controller_test.exs | 145 ++++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) 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 0d0557469b..e22a445296 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 @@ -97,8 +97,13 @@ defmodule BlockScoutWeb.API.RPC.ContractView do external_libraries = Map.get(contract, :external_libraries, []) if Enum.count(external_libraries) > 0 do + external_libraries_without_id = + Enum.map(external_libraries, fn %{name: name, address_hash: address_hash} -> + %{"name" => name, "address_hash" => address_hash} + end) + contract_output - |> Map.put_new(:ExternalLibraries, external_libraries) + |> Map.put_new(:ExternalLibraries, external_libraries_without_id) else contract_output end diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs index f4af65e9ac..5c12c1e5db 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs @@ -1,5 +1,6 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do use BlockScoutWeb.ConnCase + alias Explorer.Chain.SmartContract alias Explorer.{Chain, Factory} describe "listcontracts" do @@ -455,6 +456,150 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do assert response["message"] == "OK" assert :ok = ExJsonSchema.Validator.validate(getsourcecode_schema(), response) end + + test "with constructor arguments", %{conn: conn} do + contract = + insert(:smart_contract, + optimization: true, + optimization_runs: 200, + evm_version: "default", + constructor_arguments: + "00000000000000000000000008e7592ce0d7ebabf42844b62ee6a878d4e1913e000000000000000000000000e1b6037da5f1d756499e184ca15254a981c92546" + ) + + params = %{ + "module" => "contract", + "action" => "getsourcecode", + "address" => to_string(contract.address_hash) + } + + expected_result = [ + %{ + "Address" => to_string(contract.address_hash), + "SourceCode" => + "/**\n* Submitted for verification at blockscout.com on #{contract.inserted_at}\n*/\n" <> + contract.contract_source_code, + "ABI" => Jason.encode!(contract.abi), + "ContractName" => contract.name, + "CompilerVersion" => contract.compiler_version, + "OptimizationUsed" => "true", + "OptimizationRuns" => 200, + "EVMVersion" => "default", + "ConstructorArguments" => + "00000000000000000000000008e7592ce0d7ebabf42844b62ee6a878d4e1913e000000000000000000000000e1b6037da5f1d756499e184ca15254a981c92546" + } + ] + + assert response = + conn + |> get("/api", params) + |> json_response(200) + + assert response["result"] == expected_result + assert response["status"] == "1" + assert response["message"] == "OK" + assert :ok = ExJsonSchema.Validator.validate(getsourcecode_schema(), response) + end + + test "with external library", %{conn: conn} do + smart_contract_bytecode = + "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582040d82a7379b1ee1632ad4d8a239954fd940277b25628ead95259a85c5eddb2120029" + + created_contract_address = + insert( + :address, + hash: "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c", + contract_code: smart_contract_bytecode + ) + + transaction = + :transaction + |> insert() + |> with_block() + + insert( + :internal_transaction_create, + transaction: transaction, + index: 0, + created_contract_address: created_contract_address, + created_contract_code: smart_contract_bytecode, + block_number: transaction.block_number, + transaction_index: transaction.index + ) + + valid_attrs = %{ + address_hash: "0x0f95fa9bc0383e699325f2658d04e8d96d87b90c", + name: "Test", + compiler_version: "0.4.23", + contract_source_code: + "pragma solidity ^0.4.23; contract SimpleStorage {uint storedData; function set(uint x) public {storedData = x; } function get() public constant returns (uint) {return storedData; } }", + abi: [ + %{ + "constant" => false, + "inputs" => [%{"name" => "x", "type" => "uint256"}], + "name" => "set", + "outputs" => [], + "payable" => false, + "stateMutability" => "nonpayable", + "type" => "function" + }, + %{ + "constant" => true, + "inputs" => [], + "name" => "get", + "outputs" => [%{"name" => "", "type" => "uint256"}], + "payable" => false, + "stateMutability" => "view", + "type" => "function" + } + ], + optimization: true, + optimization_runs: 200, + evm_version: "default" + } + + external_libraries = [ + %SmartContract.ExternalLibrary{:address_hash => "0xb18aed9518d735482badb4e8b7fd8d2ba425ce95", :name => "Test"}, + %SmartContract.ExternalLibrary{:address_hash => "0x283539e1b1daf24cdd58a3e934d55062ea663c3f", :name => "Test2"} + ] + + {:ok, %SmartContract{} = contract} = Chain.create_smart_contract(valid_attrs, external_libraries) + + params = %{ + "module" => "contract", + "action" => "getsourcecode", + "address" => to_string(contract.address_hash) + } + + expected_result = [ + %{ + "Address" => to_string(contract.address_hash), + "SourceCode" => + "/**\n* Submitted for verification at blockscout.com on #{contract.inserted_at}\n*/\n" <> + contract.contract_source_code, + "ABI" => Jason.encode!(contract.abi), + "ContractName" => contract.name, + "CompilerVersion" => contract.compiler_version, + "OptimizationUsed" => "true", + "OptimizationRuns" => 200, + "EVMVersion" => "default", + "ExternalLibraries" => [ + %{"name" => "Test", "address_hash" => "0xb18aed9518d735482badb4e8b7fd8d2ba425ce95"}, + %{"name" => "Test2", "address_hash" => "0x283539e1b1daf24cdd58a3e934d55062ea663c3f"} + ] + } + ] + + assert response = + conn + |> get("/api", params) + |> json_response(200) + + assert response["result"] == expected_result + assert response["status"] == "1" + assert response["message"] == "OK" + assert :ok = ExJsonSchema.Validator.validate(getsourcecode_schema(), response) + end end describe "verify" do From 30132a71a9e17173d67629ec1972be51c82ab28b Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Tue, 10 Dec 2019 16:31:27 +0300 Subject: [PATCH 5/8] CR issues --- .../block_scout_web/views/api/rpc/contract_view.ex | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) 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 e22a445296..cd0c0a7af5 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 @@ -82,17 +82,13 @@ defmodule BlockScoutWeb.API.RPC.ContractView do end end - defp set_constructor_arguments(contract_output, contract) do - constructor_arguments = Map.get(contract, :constructor_arguments, "") - - if constructor_arguments && constructor_arguments != "" do - contract_output - |> Map.put_new(:ConstructorArguments, constructor_arguments) - else - contract_output - end + defp set_constructor_arguments(contract_output, %{constructor_arguments: constructor_arguments}) do + contract_output + |> Map.put_new(:ConstructorArguments, constructor_arguments) end + defp set_constructor_arguments(contract_output, _), do: contract_output + defp set_external_libraries(contract_output, contract) do external_libraries = Map.get(contract, :external_libraries, []) From 4ed9fdd2c98205cfefe522ba26cfb6231f20d7bb Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Tue, 10 Dec 2019 17:04:03 +0300 Subject: [PATCH 6/8] Add guard is_empty_string --- .../block_scout_web/views/api/rpc/contract_view.ex | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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 cd0c0a7af5..7d92c8d5a2 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 @@ -4,6 +4,8 @@ defmodule BlockScoutWeb.API.RPC.ContractView do alias BlockScoutWeb.API.RPC.RPCView alias Explorer.Chain.{Address, DecompiledSmartContract, SmartContract} + defguardp is_empty_string(input) when input == "" or input == nil + def render("listcontracts.json", %{contracts: contracts}) do contracts = Enum.map(contracts, &prepare_contract/1) @@ -82,13 +84,14 @@ defmodule BlockScoutWeb.API.RPC.ContractView do end end - defp set_constructor_arguments(contract_output, %{constructor_arguments: constructor_arguments}) do + defp set_constructor_arguments(contract_output, %{constructor_arguments: arguments}) when is_empty_string(arguments), + do: contract_output + + defp set_constructor_arguments(contract_output, %{constructor_arguments: arguments}) do contract_output - |> Map.put_new(:ConstructorArguments, constructor_arguments) + |> Map.put_new(:ConstructorArguments, arguments) end - defp set_constructor_arguments(contract_output, _), do: contract_output - defp set_external_libraries(contract_output, contract) do external_libraries = Map.get(contract, :external_libraries, []) From 06c781d94e311e9141cb9cc1550e353cff0f670e Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Tue, 10 Dec 2019 18:10:48 +0300 Subject: [PATCH 7/8] Missing function clause for set_constructor_arguments --- .../lib/block_scout_web/views/api/rpc/contract_view.ex | 2 ++ 1 file changed, 2 insertions(+) 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 7d92c8d5a2..41a0b7734d 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 @@ -92,6 +92,8 @@ defmodule BlockScoutWeb.API.RPC.ContractView do |> Map.put_new(:ConstructorArguments, arguments) end + defp set_constructor_arguments(contract_output, _), do: contract_output + defp set_external_libraries(contract_output, contract) do external_libraries = Map.get(contract, :external_libraries, []) From 92e496365136e43a25240f8df85f3ceafa0ed212 Mon Sep 17 00:00:00 2001 From: Victor Baranov Date: Tue, 10 Dec 2019 18:58:51 +0300 Subject: [PATCH 8/8] Add tokenID for tokentx action --- CHANGELOG.md | 3 +-- .../lib/block_scout_web/etherscan.ex | 7 +++++++ .../views/api/rpc/address_view.ex | 19 +++++++++++++------ .../api/rpc/address_controller_test.exs | 3 ++- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8b458a9d..83af597aa3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,13 @@ ## Current ### Features +- [#2918](https://github.com/poanetwork/blockscout/pull/2918) - Add tokenID for tokentx API action ### Fixes - [#2906](https://github.com/poanetwork/blockscout/pull/2906) - fix address sum cache - - [#2902](https://github.com/poanetwork/blockscout/pull/2902) - Offset in blocks retrieval for average block time ### Chore - - [#2896](https://github.com/poanetwork/blockscout/pull/2896) - Disable Parity websockets tests diff --git a/apps/block_scout_web/lib/block_scout_web/etherscan.ex b/apps/block_scout_web/lib/block_scout_web/etherscan.ex index abb358179c..5e6c05bb41 100644 --- a/apps/block_scout_web/lib/block_scout_web/etherscan.ex +++ b/apps/block_scout_web/lib/block_scout_web/etherscan.ex @@ -589,6 +589,12 @@ defmodule BlockScoutWeb.Etherscan do example: ~s("Some Token Name") } + @token_id_type %{ + type: "integer", + definition: "id of token", + example: ~s("0") + } + @token_symbol_type %{ type: "string", definition: "Trading symbol of the token.", @@ -752,6 +758,7 @@ defmodule BlockScoutWeb.Etherscan do example: ~s("663046792267785498951364") }, tokenName: @token_name_type, + tokenID: @token_id_type, tokenSymbol: @token_symbol_type, tokenDecimal: @token_decimal_type, transactionIndex: @transaction_index_type, diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex index 8063b1db40..62da759428 100644 --- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex +++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/address_view.ex @@ -121,7 +121,7 @@ defmodule BlockScoutWeb.API.RPC.AddressView do } end - defp prepare_token_transfer(token_transfer) do + defp prepare_common_token_transfer(token_transfer) do %{ "blockNumber" => to_string(token_transfer.block_number), "timeStamp" => to_string(DateTime.to_unix(token_transfer.block_timestamp)), @@ -132,7 +132,6 @@ defmodule BlockScoutWeb.API.RPC.AddressView do "contractAddress" => to_string(token_transfer.token_contract_address_hash), "to" => to_string(token_transfer.to_address_hash), "logIndex" => to_string(token_transfer.token_log_index), - "value" => get_token_value(token_transfer), "tokenName" => token_transfer.token_name, "tokenSymbol" => token_transfer.token_symbol, "tokenDecimal" => to_string(token_transfer.token_decimals), @@ -146,12 +145,20 @@ defmodule BlockScoutWeb.API.RPC.AddressView do } end - defp get_token_value(%{token_type: "ERC-721"} = token_transfer) do - to_string(token_transfer.token_id) + defp prepare_token_transfer(%{token_type: "ERC-721"} = token_transfer) do + token_transfer + |> prepare_common_token_transfer() + |> Map.put_new(:tokenID, token_transfer.token_id) + end + + defp prepare_token_transfer(%{token_type: "ERC-20"} = token_transfer) do + token_transfer + |> prepare_common_token_transfer() + |> Map.put_new(:value, to_string(token_transfer.amount)) end - defp get_token_value(token_transfer) do - to_string(token_transfer.amount) + defp prepare_token_transfer(token_transfer) do + prepare_common_token_transfer(token_transfer) end defp prepare_block(block) do diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs index 5b873bed10..2db1bdb33c 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs @@ -1807,7 +1807,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do |> get("/api", params) |> json_response(200) - assert result["value"] == to_string(token_transfer.token_id) + assert result["tokenID"] == to_string(token_transfer.token_id) assert response["status"] == "1" assert response["message"] == "OK" assert :ok = ExJsonSchema.Validator.validate(tokentx_schema(), response) @@ -2618,6 +2618,7 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do "logIndex" => %{"type" => "string"}, "value" => %{"type" => "string"}, "tokenName" => %{"type" => "string"}, + "tokenID" => %{"type" => "string"}, "tokenSymbol" => %{"type" => "string"}, "tokenDecimal" => %{"type" => "string"}, "transactionIndex" => %{"type" => "string"},