Add contract creator on Account details page

Now the user will be able to see the contract creator and the
transaction references to it on the Account details page when the
address is a contract.

In order to this work we had to make a query that returns the internal
transaction that has the contract creation. This way we can get the
`from_address` that represents the contract creator and the transaction
from the internal transaction.
pull/362/head
Felipe Renan 6 years ago committed by Felipe Renan
parent 45499cbb4c
commit ceb971b285
  1. 4
      apps/explorer/lib/explorer/chain.ex
  2. 8
      apps/explorer/lib/explorer/chain/address.ex
  3. 4
      apps/explorer/test/explorer/chain_test.exs
  4. 1
      apps/explorer_web/lib/explorer_web/controllers/address_transaction_controller.ex
  5. 30
      apps/explorer_web/lib/explorer_web/templates/address/overview.html.eex
  6. 10
      apps/explorer_web/priv/gettext/default.pot
  7. 10
      apps/explorer_web/priv/gettext/en/LC_MESSAGES/default.po
  8. 15
      apps/explorer_web/test/explorer_web/controllers/address_contract_controller_test.exs
  9. 4
      apps/explorer_web/test/explorer_web/features/pages/address_page.ex
  10. 57
      apps/explorer_web/test/explorer_web/features/viewing_addresses_test.exs

@ -622,7 +622,7 @@ defmodule Explorer.Chain do
query = query =
from( from(
address in Address, address in Address,
preload: [:smart_contract], preload: [:smart_contract, :contracts_creation_internal_transaction],
where: address.hash == ^hash where: address.hash == ^hash
) )
@ -638,7 +638,7 @@ defmodule Explorer.Chain do
query = query =
from( from(
address in Address, address in Address,
preload: [:smart_contract], preload: [:smart_contract, :contracts_creation_internal_transaction],
where: address.hash == ^hash and not is_nil(address.contract_code) where: address.hash == ^hash and not is_nil(address.contract_code)
) )

@ -6,7 +6,7 @@ defmodule Explorer.Chain.Address do
use Explorer.Schema use Explorer.Schema
alias Ecto.Changeset alias Ecto.Changeset
alias Explorer.Chain.{Block, Data, Hash, Wei, SmartContract} alias Explorer.Chain.{Block, Data, Hash, Wei, SmartContract, InternalTransaction}
@optional_attrs ~w(contract_code)a @optional_attrs ~w(contract_code)a
@required_attrs ~w(hash)a @required_attrs ~w(hash)a
@ -43,6 +43,12 @@ defmodule Explorer.Chain.Address do
has_one(:smart_contract, SmartContract) has_one(:smart_contract, SmartContract)
has_one(
:contracts_creation_internal_transaction,
InternalTransaction,
foreign_key: :created_contract_address_hash
)
timestamps() timestamps()
end end

@ -832,7 +832,9 @@ defmodule Explorer.ChainTest do
end end
test "finds an contract address" do test "finds an contract address" do
address = insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil) address =
insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil)
|> Repo.preload(:contracts_creation_internal_transaction)
response = Chain.find_contract_address(address.hash) response = Chain.find_contract_address(address.hash)

@ -26,7 +26,6 @@ defmodule ExplorerWeb.AddressTransactionController do
|> Keyword.merge(current_filter(params)) |> Keyword.merge(current_filter(params))
transactions_plus_one = Chain.address_to_transactions(address, full_options) transactions_plus_one = Chain.address_to_transactions(address, full_options)
{transactions, next_page} = split_list_by_page(transactions_plus_one) {transactions, next_page} = split_list_by_page(transactions_plus_one)
render( render(

@ -19,6 +19,35 @@
<h3 class="<%= if ExplorerWeb.AddressView.contract?(@address) do %>contract-address<% end %>" data-test="address_detail_hash"><%= @address %></h3> <h3 class="<%= if ExplorerWeb.AddressView.contract?(@address) do %>contract-address<% end %>" data-test="address_detail_hash"><%= @address %></h3>
<div class="d-flex flex-row justify-content-start text-muted"> <div class="d-flex flex-row justify-content-start text-muted">
<span class="mr-4" data-test="transaction_count"><%= Cldr.Number.to_string!(@transaction_count) %> <%= gettext "Transactions" %></span> <span class="mr-4" data-test="transaction_count"><%= Cldr.Number.to_string!(@transaction_count) %> <%= gettext "Transactions" %></span>
<%= if contract?(@address) do %>
<span class="mr-4" data-test="address_contract_creator">
<%= gettext "Contract created by" %>
<%= link(
trimmed_hash(@address.contracts_creation_internal_transaction.from_address_hash),
to: address_path(
ExplorerWeb.Endpoint,
:show,
@locale,
@address.contracts_creation_internal_transaction.from_address_hash
)
) %>
<%= gettext "at" %>
<%= link(
trimmed_hash(@address.contracts_creation_internal_transaction.transaction_hash),
to: transaction_path(
ExplorerWeb.Endpoint,
:show,
@locale,
@address.contracts_creation_internal_transaction.transaction_hash
),
"data-test": "transaction_hash_link",
"class": "tile-title"
) %>
</span>
<% end %>
</div> </div>
</div> </div>
</div> </div>
@ -38,7 +67,6 @@
</div> </div>
</section> </section>
<!-- Modal --> <!-- Modal -->
<div class="modal fade" id="qrModal" tabindex="-1" role="dialog" aria-labelledby="qrModalLabel" aria-hidden="true"> <div class="modal fade" id="qrModal" tabindex="-1" role="dialog" aria-labelledby="qrModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm" role="document"> <div class="modal-dialog modal-sm" role="document">

@ -633,3 +633,13 @@ msgstr ""
#: lib/explorer_web/views/transaction_view.ex:112 #: lib/explorer_web/views/transaction_view.ex:112
msgid "Contract Call" msgid "Contract Call"
msgstr "" msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address/overview.html.eex:25
msgid "Contract created by"
msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address/overview.html.eex:36
msgid "at"
msgstr ""

@ -645,3 +645,13 @@ msgstr ""
#: lib/explorer_web/views/transaction_view.ex:112 #: lib/explorer_web/views/transaction_view.ex:112
msgid "Contract Call" msgid "Contract Call"
msgstr "" msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address/overview.html.eex:25
msgid "Contract created by"
msgstr ""
#, elixir-format
#: lib/explorer_web/templates/address/overview.html.eex:36
msgid "at"
msgstr ""

@ -24,7 +24,7 @@ defmodule ExplorerWeb.AddressContractControllerTest do
assert html_response(conn, 404) assert html_response(conn, 404)
end end
test "returns not found when the address doesn't have a contract", %{conn: conn} do test "returns not found when the address isn't a contract", %{conn: conn} do
address = insert(:address) address = insert(:address)
conn = get(conn, address_contract_path(ExplorerWeb.Endpoint, :index, :en, address)) conn = get(conn, address_contract_path(ExplorerWeb.Endpoint, :index, :en, address))
@ -32,13 +32,22 @@ defmodule ExplorerWeb.AddressContractControllerTest do
assert html_response(conn, 404) assert html_response(conn, 404)
end end
test "suscefully renders the page", %{conn: conn} do test "successfully renders the page when the address is a contract", %{conn: conn} do
address = insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil) address = insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil)
transaction = insert(:transaction, from_address: address)
insert(
:internal_transaction_create,
index: 0,
transaction: transaction,
created_contract_address: address
)
conn = get(conn, address_contract_path(ExplorerWeb.Endpoint, :index, :en, address)) conn = get(conn, address_contract_path(ExplorerWeb.Endpoint, :index, :en, address))
assert html_response(conn, 200) assert html_response(conn, 200)
assert address == conn.assigns.address assert address.hash == conn.assigns.address.hash
assert %Token{} = conn.assigns.exchange_rate assert %Token{} = conn.assigns.exchange_rate
assert conn.assigns.transaction_count assert conn.assigns.transaction_count
end end

@ -15,6 +15,10 @@ defmodule ExplorerWeb.AddressPage do
css("[data-test='address_balance']") css("[data-test='address_balance']")
end end
def contract_creator do
css("[data-test='address_contract_creator']")
end
def click_internal_transactions(session) do def click_internal_transactions(session) do
click(session, css("[data-test='internal_transactions_tab_link']")) click(session, css("[data-test='internal_transactions_tab_link']"))
end end

@ -48,6 +48,63 @@ defmodule ExplorerWeb.ViewingAddressesTest do
|> assert_text(AddressPage.balance(), "0.0000000000000005 POA") |> assert_text(AddressPage.balance(), "0.0000000000000005 POA")
end end
describe "viewing contract creator" do
test "see the contract creator and transaction links", %{session: session} do
address = insert(:address)
transaction = insert(:transaction, from_address: address)
contract = insert(:address, contract_code: Explorer.Factory.data("contract_code"))
internal_transaction =
insert(
:internal_transaction_create,
index: 0,
transaction: transaction,
from_address: address,
created_contract_address: contract
)
address_hash = ExplorerWeb.AddressView.trimmed_hash(address.hash)
transaction_hash = ExplorerWeb.AddressView.trimmed_hash(transaction.hash)
session
|> AddressPage.visit_page(internal_transaction.created_contract_address)
|> assert_text(AddressPage.contract_creator(), "#{address_hash} at #{transaction_hash}")
end
test "see the contract creator and transaction links even when the creator is another contract", %{session: session} do
lincoln = insert(:address)
contract = insert(:address, contract_code: Explorer.Factory.data("contract_code"))
transaction = insert(:transaction)
another_contract = insert(:address, contract_code: Explorer.Factory.data("contract_code"))
insert(
:internal_transaction,
index: 0,
transaction: transaction,
from_address: lincoln,
to_address: contract,
created_contract_address: contract,
type: :call
)
internal_transaction =
insert(
:internal_transaction_create,
index: 1,
transaction: transaction,
from_address: contract,
created_contract_address: another_contract
)
contract_hash = ExplorerWeb.AddressView.trimmed_hash(contract.hash)
transaction_hash = ExplorerWeb.AddressView.trimmed_hash(transaction.hash)
session
|> AddressPage.visit_page(internal_transaction.created_contract_address)
|> assert_text(AddressPage.contract_creator(), "#{contract_hash} at #{transaction_hash}")
end
end
describe "viewing transactions" do describe "viewing transactions" do
test "sees all addresses transactions by default", %{ test "sees all addresses transactions by default", %{
addresses: addresses, addresses: addresses,

Loading…
Cancel
Save