From efdd82e8d8ff279bda9fb822feea0d94b4b9d088 Mon Sep 17 00:00:00 2001 From: Ayrat Badykov Date: Wed, 28 Aug 2019 15:06:05 +0300 Subject: [PATCH] fetch ERC721 token instance by token_id --- .../controllers/tokens/instance_controller.ex | 16 ++++++++++++++++ .../lib/block_scout_web/web_router.ex | 7 +++++++ apps/explorer/lib/explorer/chain.ex | 15 +++++++++++++++ apps/explorer/test/explorer/chain_test.exs | 19 +++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance_controller.ex diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance_controller.ex new file mode 100644 index 0000000000..2c2d1f6f2e --- /dev/null +++ b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance_controller.ex @@ -0,0 +1,16 @@ +defmodule BlockScoutWeb.Tokens.InstanceController do + use BlockScoutWeb, :controller + + alias Explorer.Chain + + def show(conn, %{"id" => token_id, "token_address_hash" => token_address_hash}) do + with {:ok, token_address} <- Chain.hash_to_address(token_address_hash, []), + {:ok, token_transfer} <- + Chain.erc721_token_instance_from_token_id_and_token_address(token_id, token_address.hash) do + json(conn, token_transfer) + else + _ -> + not_found(conn) + end + end +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 1bbd57d041..18589ca0e1 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 @@ -178,6 +178,13 @@ defmodule BlockScoutWeb.WebRouter do only: [:index], as: :inventory ) + + resources( + "/token_instance", + Tokens.InstanceController, + only: [:show], + as: :instance + ) end resources( diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index 58253c0f27..6c59dc2847 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -2959,6 +2959,21 @@ defmodule Explorer.Chain do |> Repo.all() end + @spec erc721_token_instance_from_token_id_and_token_address(binary(), Hash.Address.t()) :: TokenTransfer.t() | nil + def erc721_token_instance_from_token_id_and_token_address(token_id, token_contract_address) do + query = + from(tt in TokenTransfer, + where: tt.token_contract_address_hash == ^token_contract_address and tt.token_id == ^token_id, + order_by: [desc: tt.block_number], + limit: 1 + ) + + case Repo.one(query) do + nil -> {:error, :not_found} + token_instance -> {:ok, token_instance} + end + end + @spec address_to_coin_balances(Hash.Address.t(), [paging_options]) :: [] def address_to_coin_balances(address_hash, options) do paging_options = Keyword.get(options, :paging_options, @default_paging_options) diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index f49be6da4e..5fa5b58f7d 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -82,6 +82,25 @@ defmodule Explorer.ChainTest do end end + describe "ERC721_token_instance_from_token_id_and_token_address/2" do + test "return ERC721 token instance" do + contract_address = insert(:address) + + token_id = 10 + + insert(:token_transfer, + from_address: contract_address, + token_contract_address: contract_address, + token_id: token_id + ) + + assert {:ok, result} = + Chain.erc721_token_instance_from_token_id_and_token_address(token_id, contract_address.hash) + + assert result.token_id == Decimal.new(token_id) + end + end + describe "address_to_logs/2" do test "fetches logs" do %Address{hash: address_hash} = address = insert(:address)