Skip to content

Commit

Permalink
Merge pull request #6582 from blockscout/va-tx-actions
Browse files Browse the repository at this point in the history
Transaction actions indexer
  • Loading branch information
vbaranov authored Feb 3, 2023
2 parents 4eb2fe3 + 81bb151 commit 84b6c72
Show file tree
Hide file tree
Showing 33 changed files with 2,004 additions and 334 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [#6721](https://github.com/blockscout/blockscout/pull/6721) - Implement fetching internal transactions from callTracer
- [#6541](https://github.com/blockscout/blockscout/pull/6541) - Integrate sig provider
- [#6712](https://github.com/blockscout/blockscout/pull/6712) - API v2 update
- [#6582](https://github.com/blockscout/blockscout/pull/6582) - Transaction actions indexer

### Fixes

Expand Down Expand Up @@ -2215,4 +2216,4 @@ Reverting of synchronous block counter, implemented in #1848

- [https://github.com/blockscout/blockscout/pull/1532](https://github.com/blockscout/blockscout/pull/1532) - Upgrade elixir to 1.8.1
- [https://github.com/blockscout/blockscout/pull/1553](https://github.com/blockscout/blockscout/pull/1553) - Dockerfile: remove 1.7.1 version pin FROM bitwalker/alpine-elixir-phoenix
- [https://github.com/blockscout/blockscout/pull/1465](https://github.com/blockscout/blockscout/pull/1465) - Resolve lodash security alert
- [https://github.com/blockscout/blockscout/pull/1465](https://github.com/blockscout/blockscout/pull/1465) - Resolve lodash security alert
28 changes: 28 additions & 0 deletions apps/block_scout_web/assets/css/components/_transaction.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,34 @@
}
}

.actions-item {
margin-bottom: 4px;
display: inline-block;

i {
font-size: 10px;
}
&.subitem {
margin-left: 10px;
}
}

.actions-list-mobile-container {
@include media-breakpoint-down(sm) {
margin-top: 0.5rem;
}
}

#actions-list-scroll-note {
padding-left: 19px;
font-size: 11px;
display: none;

@media (max-width: $breakpoint-md) {
padding-left: 0;
}
}

.transfers-list-mobile-container {
@include media-breakpoint-down(sm) {
margin-top: 0.5rem;
Expand Down
35 changes: 35 additions & 0 deletions apps/block_scout_web/assets/css/custom-scrollbar.scss

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions apps/block_scout_web/assets/js/lib/custom_scrollbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import $ from 'jquery'
import 'malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min'

$(function () {
const scrollBar = $('.mCustomScrollbar')
scrollBar.mCustomScrollbar({
callbacks: {
onOverflowY: () => {
$('#actions-list-scroll-note').css('display', 'block')
scrollBar.removeClass('mCS_no_scrollbar_y')
},
onOverflowYNone: () => {
$('#actions-list-scroll-note').css('display', 'none')
scrollBar.addClass('mCS_no_scrollbar_y')
}
},
theme: 'dark',
autoHideScrollbar: true,
scrollButtons: { enable: false },
scrollbarPosition: 'outside'
})
})
70 changes: 68 additions & 2 deletions apps/block_scout_web/assets/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/block_scout_web/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"lodash.rangeright": "^4.2.0",
"lodash.reduce": "^4.6.0",
"luxon": "^3.2.1",
"malihu-custom-scrollbar-plugin": "3.1.5",
"mixpanel-browser": "^2.45.0",
"moment": "^2.29.4",
"nanomorph": "^5.4.0",
Expand Down
2 changes: 2 additions & 0 deletions apps/block_scout_web/assets/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ const appJs =
'text-ad': './js/lib/text_ad.js',
'banner': './js/lib/banner.js',
'autocomplete': './js/lib/autocomplete.js',
'custom-scrollbar': './js/lib/custom_scrollbar.js',
'custom-scrollbar-styles': './css/custom-scrollbar.scss',
'search-results': './js/pages/search-results/search.js',
'token-overview': './js/pages/token/overview.js',
'export-csv': './css/export-csv.scss',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
{:not_found,
Chain.hash_to_transaction(
transaction_hash,
necessity_by_association: @transaction_necessity_by_association
necessity_by_association: Map.put(@transaction_necessity_by_association, :transaction_actions, :optional)
)},
{:ok, false} <- AccessHelpers.restricted_access?(to_string(transaction.from_address_hash), params),
{:ok, false} <- AccessHelpers.restricted_access?(to_string(transaction.to_address_hash), params),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<link rel="preload" href="<%= static_path(@conn, "/js/chain.js") %>" as="script">
<link rel="preload" href="<%= static_path(@conn, "/js/chart-loader.js") %>" as="script">
<link rel="preload" href="<%= static_path(@conn, "/js/token-transfers-toggle.js") %>" as="script">
<% Elixir.BlockScoutWeb.TransactionView -> %>
<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
<link rel="stylesheet" href="<%= static_path(@conn, "/css/custom-scrollbar-styles.css") %>">
<link rel="preload" href="<%= static_path(@conn, "/js/custom-scrollbar.js") %>" as="script">
<% _ -> %>
<link rel="stylesheet" href="<%= static_path(@conn, "/css/app.css") %>">
<% end %>
Expand Down Expand Up @@ -238,6 +242,9 @@
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/chart-loader.js") %>"></script>
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/token-transfers-toggle.js") %>"></script>
<% end %>
<%= if @view_module == Elixir.BlockScoutWeb.TransactionView do %>
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/custom-scrollbar.js") %>"></script>
<% end %>
<script defer src="<%= static_path(@conn, "/js/autocomplete.js") %>"></script>
<%= if @view_module in [Elixir.BlockScoutWeb.AddressContractVerificationView, Elixir.BlockScoutWeb.AddressContractVerificationVyperView, Elixir.BlockScoutWeb.AddressContractVerificationViaFlattenedCodeView, Elixir.BlockScoutWeb.AddressContractVerificationViaMultiPartFilesView, Elixir.BlockScoutWeb.AddressContractVerificationViaJsonView, Elixir.BlockScoutWeb.AddressContractVerificationViaStandardJsonInputView] do %>
<script defer data-cfasync="false" src="<%= static_path(@conn, "/js/verification-form.js") %>"></script>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<%= if @action.protocol == :uniswap_v3 do %>
<%= if @action.type == :mint_nft do %>
<div class="<%= if @isLast, do: "lastItem", else: "" %>">
<span class="actions-item">
<i class="fa fa-caret-right"></i>

<% address_string = Map.get(@action.data, "address") %>
<% {address_status, address} = transaction_action_string_to_address(address_string) %>
<% address = if address_status == :ok, do: render_to_string(BlockScoutWeb.AddressView, "_link.html", address: address, contract: BlockScoutWeb.AddressView.contract?(address), use_custom_tooltip: false, trimmed: false), else: render_to_string(BlockScoutWeb.TransactionView, "_actions_address.html", address_string: address_string, action: @action) %>
<% to_address = Map.get(@action.data, "to") %>
<% to_content = raw(render_to_string BlockScoutWeb.TransactionView, "_actions_to.html", address: to_address) %>
<% to = link to: address_path(BlockScoutWeb.Endpoint, :show, to_address), "data-test": "address_hash_link", do: to_content %>

<%= gettext("Mint of %{address} <span class=\"text-muted\">To</span> %{to}", address: address, to: safe_to_string(to)) |> raw() %>
</span>
<br />

<% token_ids = Map.get(@action.data, "ids") %>
<%= for id <- token_ids do %>
<span class="actions-item subitem">
<i class="fa fa-caret-right"></i>
<% link_to_id = link id, to: token_instance_path(BlockScoutWeb.Endpoint, :show, address_string, id), "data-test": "token_link" %>
<%= gettext("%{qty} of <span class=\"text-muted\">Token ID [%{link_to_id}]</span>", qty: 1, link_to_id: safe_to_string(link_to_id)) |> raw() %>
</span>
<br />
<% end %>
</div>
<% end %>
<%= if Enum.member?([:mint, :burn, :collect, :swap], @action.type) do %>
<div class="<%= if @isLast, do: "lastItem", else: "" %>">
<span class="actions-item">
<% amount0 = formatted_action_amount(@action.data, "amount0") %>
<% amount1 = formatted_action_amount(@action.data, "amount1") %>

<% symbol0 = Map.get(@action.data, "symbol0") %>
<% address0 = Map.get(@action.data, "address0") %>
<% symbol1 = Map.get(@action.data, "symbol1") %>
<% address1 = Map.get(@action.data, "address1") %>

<i class="fa fa-caret-right"></i>

<% symbol0 = if symbol0 != "Ether", do: link(symbol0, to: token_path(BlockScoutWeb.Endpoint, :show, address0), "data-test": "token_link"), else: raw(symbol0) %>

<% symbol1 = if symbol1 != "Ether", do: link(symbol1, to: token_path(BlockScoutWeb.Endpoint, :show, address1), "data-test": "token_link"), else: raw(symbol1) %>

<%= if @action.type == :mint do %>
<%= render BlockScoutWeb.TransactionView, "_actions_uniswap.html", action: "Add", amount0: amount0, symbol0: symbol0, conjunction: "And", amount1: amount1, symbol1: symbol1, tail: "Liquidity To Uniswap V3" %>
<% end %>
<%= if @action.type == :burn do %>
<%= render BlockScoutWeb.TransactionView, "_actions_uniswap.html", action: "Remove", amount0: amount0, symbol0: symbol0, conjunction: "And", amount1: amount1, symbol1: symbol1, tail: "Liquidity From Uniswap V3" %>
<% end %>
<%= if @action.type == :collect do %>
<%= render BlockScoutWeb.TransactionView, "_actions_uniswap.html", action: "Collect", amount0: amount0, symbol0: symbol0, conjunction: "And", amount1: amount1, symbol1: symbol1, tail: "From Uniswap V3" %>
<% end %>
<%= if @action.type == :swap do %>
<%= render BlockScoutWeb.TransactionView, "_actions_uniswap.html", action: "Swap", amount0: amount0, symbol0: symbol0, conjunction: "For", amount1: amount1, symbol1: symbol1, tail: "On Uniswap V3" %>
<% end %>
</span>
<br />
</div>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%= link to: address_path(BlockScoutWeb.Endpoint, :show, @address_string), "data-test": "address_hash_link" do %>
<% name = Map.get(@action.data, "name") %>
<span data-toggle="tooltip" data-placement="top" title="<%= name %>">
<span class="d-none d-md-none d-lg-inline d-xl-inline"><%= AddressView.short_string(name, 15) %></span>
<span class="d-inline d-md-inline d-lg-none d-xl-none"><%= AddressView.short_string(name, 5) %></span>
</span>

<% symbol = Map.get(@action.data, "symbol") %>
<span data-toggle="tooltip" data-placement="top" title="<%= symbol %>">
<span class="d-none d-md-none d-lg-inline d-xl-inline">(<%= AddressView.short_string(symbol, 15) %>)</span>
<span class="d-inline d-md-inline d-lg-none d-xl-none">(<%= AddressView.short_string(symbol, 5) %>)</span>
</span>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<span data-toggle="tooltip" data-placement="top" title="<%= @address %>">
<span class="d-none d-md-none d-xl-inline"><%= @address %></span>
<span class="d-md-inline-block d-xl-none"><%= BlockScoutWeb.AddressView.trimmed_hash(@address) %></span>
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<span class="text-muted"><%= @action %></span> <%= @amount0 %> <%= @symbol0 %> <span class="text-muted"><%= @conjunction %></span> <%= @amount1 %> <%= @symbol1 %> <span class="text-muted"><%= @tail %></span>
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,29 @@
</dd>
</dl>
<% end %>
<!-- Transaction Action -->
<% %{transaction_actions: transaction_actions} = transaction_actions(@transaction) %>
<%= if not Enum.empty?(transaction_actions) do %>
<dl class="row">
<dt class="col-sm-3 col-lg-2 text-muted">
<%= render BlockScoutWeb.CommonComponentsView, "_i_tooltip_2.html",
text: gettext("Highlighted events of the transaction.") %>
<%= gettext "Transaction Action" %>
<p id="actions-list-scroll-note"><%= gettext "Scroll to see more" %></p>
</dt>
<dd class="col-sm-9 col-lg-10 actions-list-mobile-container">
<div class="mCustomScrollbar" style="max-height:100px;width:90%">
<% transaction_actions_indexed = Enum.with_index(transaction_actions) %>
<% transaction_actions_length = Enum.count(transaction_actions) %>
<%= for {action, i} <- transaction_actions_indexed do %>
<% action_assigns = Map.put(assigns, :action, action) %>
<% action_assigns = Map.put(action_assigns, :isLast, (i == transaction_actions_length - 1)) %>
<%= render BlockScoutWeb.TransactionView, "_actions.html", action_assigns %>
<% end %>
</div>
</dd>
</dl>
<% end %>
<!-- From -->
<dl class="row">
<dt class="col-sm-3 col-lg-2 text-muted">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
prepare_token_transfer(token_transfer, conn)
end

def render("transaction_actions.json", %{actions: actions}) do
Enum.map(actions, &prepare_transaction_action(&1))
end

def render("internal_transactions.json", %{
internal_transactions: internal_transactions,
next_page_params: next_page_params,
Expand Down Expand Up @@ -102,6 +106,14 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
}
end

def prepare_transaction_action(action) do
%{
"protocol" => action.protocol,
"type" => action.type,
"data" => action.data
}
end

def prepare_token_transfer_total(token_transfer) do
case Helpers.token_transfer_amount_for_api(token_transfer) do
{:ok, :erc721_instance} ->
Expand Down Expand Up @@ -244,6 +256,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
"decoded_input" => decoded_input_data,
"token_transfers" => token_transfers(transaction.token_transfers, conn, single_tx?),
"token_transfers_overflow" => token_transfers_overflow(transaction.token_transfers, single_tx?),
"actions" => transaction_actions(transaction.transaction_actions),
"exchange_rate" => (Market.get_exchange_rate(Explorer.coin()) || TokenRate.null()).usd_value,
"method" => method_name(transaction, decoded_input),
"tx_types" => tx_types(transaction),
Expand All @@ -267,6 +280,12 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
def token_transfers_overflow(token_transfers, _),
do: Enum.count(token_transfers) > Chain.get_token_transfers_per_transaction_preview_count()

defp transaction_actions(%NotLoaded{}), do: []

defp transaction_actions(actions) do
render("transaction_actions.json", %{actions: actions})
end

defp priority_fee_per_gas(max_priority_fee_per_gas, base_fee_per_gas, max_fee_per_gas) do
if is_nil(max_priority_fee_per_gas) or is_nil(base_fee_per_gas),
do: nil,
Expand Down
Loading

0 comments on commit 84b6c72

Please sign in to comment.