Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/block_scout_web/assets/css/_typography.scss
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,4 @@ textarea.form-control {
[data-transaction-status^="Error"],
[data-internal-transaction-type="Suicide"] {
color: $danger;
}
}
6 changes: 5 additions & 1 deletion apps/block_scout_web/assets/css/components/_tile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ $tile-body-a-color: #5959d8 !default;

@mixin generate-tile-block($prefix, $color, $label-color: false) {
&#{ $prefix } {
border-left: 4px solid $color;
border-left: 4px solid $color !important;

.tile-transaction-type-block {
a {
Expand Down Expand Up @@ -246,6 +246,10 @@ $tile-body-a-color: #5959d8 !default;
".tile-type-internal-transaction",
$tile-type-internal-transaction-color
);
@include generate-tile-block(
".tile-type-internal-transaction-outside",
$cyan
);
@include generate-tile-block(
".tile-type-api-documentation",
$tile-type-api-documentation-color
Expand Down
16 changes: 16 additions & 0 deletions apps/block_scout_web/lib/block_scout_web/schema/scalars.ex
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@ defmodule BlockScoutWeb.Schema.Scalars do
value(:callcode)
value(:delegatecall)
value(:staticcall)
value(:beforetransfer)
value(:aftertransfer)
value(:beforemint)
value(:aftermint)
value(:beforeburn)
value(:afterburn)
end

enum :purpose do
value(:fee_collection)
value(:fee_payment)
value(:deposit)
value(:escrow)
value(:prepaid)
value(:refund)
value(:l1_send)
end

enum :type do
Expand Down
1 change: 1 addition & 0 deletions apps/block_scout_web/lib/block_scout_web/schema/types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ defmodule BlockScoutWeb.Schema.Types do
"""
node object(:internal_transaction, id_fetcher: &internal_transaction_id_fetcher/2) do
field(:call_type, :call_type)
field(:purpose, :purpose)
field(:created_contract_code, :data)
field(:error, :string)
field(:gas, :decimal)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
<% error = @internal_transaction.error %>
<div class="tile tile-type-internal-transaction fade-in <%= if error, do: "tile-status--error--reason"%>" data-test="internal_transaction" data-key="<%= @internal_transaction.transaction_hash %>_<%= @internal_transaction.index %>" data-internal-transaction-transaction-hash="<%= @internal_transaction.transaction_hash %>" data-internal-transaction-index="<%= @internal_transaction.index %>">
<div class="tile
fade-in <%= if error, do: "tile-status--error--reason"%>
<%= case @internal_transaction.call_type do
:beforetransfer -> "tile-type-internal-transaction-outside"
:aftertransfer -> "tile-type-internal-transaction-outside"
:beforemint -> "tile-type-internal-transaction-outside"
:aftermint -> "tile-type-internal-transaction-outside"
:beforeburn -> "tile-type-internal-transaction-outside"
:afterburn -> "tile-type-internal-transaction-outside"
_ -> "tile-type-internal-transaction"
end
%>"
data-test="internal_transaction" data-key="<%= @internal_transaction.transaction_hash %>_<%= @internal_transaction.index %>" data-internal-transaction-transaction-hash="<%= @internal_transaction.transaction_hash %>" data-internal-transaction-index="<%= @internal_transaction.index %>">
<div class="row tile-body">
<!-- Color Block -->
<div class="tile-transaction-type-block col-md-2 d-flex flex-row flex-md-column">
Expand All @@ -15,9 +27,17 @@
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<%= render BlockScoutWeb.TransactionView, "_link.html", transaction_hash: @internal_transaction.transaction_hash %>
<span class="text-nowrap">
<%= if !Enum.member?([:beforemint, :aftermint], @internal_transaction.call_type) do %>
<%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:from, assigns[:current_address]) |> BlockScoutWeb.RenderHelpers.render_partial() %>
<% end %>

<%= if !Enum.member?([:beforemint, :aftermint, :beforeburn, :afterburn], @internal_transaction.call_type) do %>
&rarr;
<% end %>

<%= if !Enum.member?([:beforeburn, :afterburn], @internal_transaction.call_type) do %>
<%= @internal_transaction |> BlockScoutWeb.AddressView.address_partial_selector(:to, assigns[:current_address]) |> BlockScoutWeb.RenderHelpers.render_partial() %>
<% end %>
</span>
<span class="d-flex flex-md-row flex-column mt-3 mt-md-0">
<span class="tile-title">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ defmodule BlockScoutWeb.InternalTransactionView do
def type(%InternalTransaction{type: :call, call_type: :callcode}), do: gettext("Call Code")
def type(%InternalTransaction{type: :call, call_type: :delegatecall}), do: gettext("Delegate Call")
def type(%InternalTransaction{type: :call, call_type: :staticcall}), do: gettext("Static Call")
def type(%InternalTransaction{type: :call, call_type: :beforetransfer}), do: gettext("Transfer before EVM")
def type(%InternalTransaction{type: :call, call_type: :aftertransfer}), do: gettext("Transfer after EVM")
def type(%InternalTransaction{type: :call, call_type: :beforemint}), do: gettext("Mint before EVM")
def type(%InternalTransaction{type: :call, call_type: :aftermint}), do: gettext("Mint after EVM")
def type(%InternalTransaction{type: :call, call_type: :beforeburn}), do: gettext("Burn before EVM")
def type(%InternalTransaction{type: :call, call_type: :afterburn}), do: gettext("Burn after EVM")
def type(%InternalTransaction{type: :create}), do: gettext("Create")
def type(%InternalTransaction{type: :create2}), do: gettext("Create2")
def type(%InternalTransaction{type: :selfdestruct}), do: gettext("Self-Destruct")
Expand Down
12 changes: 9 additions & 3 deletions apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ defmodule EthereumJSONRPC.Geth.Call do
end

defp entry_to_elixir({key, value} = entry)
when key in ~w(callType createdContractAddressHash createdContractCode error from init input output to transactionHash type) and
when key in ~w(callType createdContractAddressHash createdContractCode error from init input output to transactionHash type purpose) and
is_binary(value),
do: entry

Expand All @@ -325,14 +325,15 @@ defmodule EthereumJSONRPC.Geth.Call do
"traceAddress" => trace_address,
"type" => "call" = type,
"callType" => call_type,
"purpose" => purpose,
"from" => from_address_hash,
"to" => to_address_hash,
"gas" => gas,
"input" => input,
"error" => error,
"value" => value
})
when call_type in ~w(call callcode delegatecall) do
when call_type in ~w(call callcode delegatecall beforetransfer aftertransfer beforemint aftermint beforeburn afterburn) do
%{
block_number: block_number,
transaction_index: transaction_index,
Expand All @@ -341,6 +342,7 @@ defmodule EthereumJSONRPC.Geth.Call do
trace_address: trace_address,
type: type,
call_type: call_type,
purpose: purpose,
from_address_hash: from_address_hash,
to_address_hash: to_address_hash,
gas: gas,
Expand All @@ -358,6 +360,7 @@ defmodule EthereumJSONRPC.Geth.Call do
"traceAddress" => trace_address,
"type" => "call" = type,
"callType" => call_type,
"purpose" => purpose,
"from" => from_address_hash,
"to" => to_address_hash,
"gas" => gas,
Expand All @@ -366,7 +369,7 @@ defmodule EthereumJSONRPC.Geth.Call do
"output" => output,
"value" => value
})
when call_type in ~w(call callcode delegatecall) do
when call_type in ~w(call callcode delegatecall beforetransfer aftertransfer beforemint aftermint beforeburn afterburn) do
%{
block_number: block_number,
transaction_index: transaction_index,
Expand All @@ -375,6 +378,7 @@ defmodule EthereumJSONRPC.Geth.Call do
trace_address: trace_address,
type: type,
call_type: call_type,
purpose: purpose,
from_address_hash: from_address_hash,
to_address_hash: to_address_hash,
gas: gas,
Expand All @@ -394,6 +398,7 @@ defmodule EthereumJSONRPC.Geth.Call do
"traceAddress" => trace_address,
"type" => "call" = type,
"callType" => "staticcall" = call_type,
"purpose" => purpose,
"from" => from_address_hash,
"to" => to_address_hash,
"input" => input,
Expand All @@ -410,6 +415,7 @@ defmodule EthereumJSONRPC.Geth.Call do
trace_address: trace_address,
type: type,
call_type: call_type,
purpose: purpose,
from_address_hash: from_address_hash,
to_address_hash: to_address_hash,
gas: gas,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ defmodule EthereumJSONRPC.Parity.Trace.Action do
end

defp entry_to_elixir({key, value} = entry)
when key in ~w(address callType from init input refundAddress to creationMethod) and is_binary(value),
when key in ~w(address callType purpose from init input refundAddress to creationMethod) and is_binary(value),
do: entry

defp entry_to_elixir({key, quantity}) when key in ~w(balance gas value) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
{
// The call stack of the EVM execution.
callStack: [{}],
transfersBeforeEVMExecution: [],
transfersAfterEVMExecution: [],

// step is invoked for every opcode that the VM executes.
step(log, db) {
Expand Down Expand Up @@ -242,13 +244,60 @@
this.topCall().error = 'execution reverted';
},

captureArbitrumTransfer(transfer) {
const before = transfer.before;
var from = "0x0000000000000000000000000000000000000000";
var to = "0x0000000000000000000000000000000000000000";
var kind = "";

if (transfer.from) {
from = transfer.from.toLowerCase();
kind = "burn";
}
if (transfer.to) {
to = transfer.to.toLowerCase();
kind = "mint";
}
if (transfer.from && transfer.to) {
kind = "transfer";
}

//const purposes = ["feeCollection", "feePayment", "deposit", "escrow", "prepaid", "refund", "l1Send"];
//var purpose = purposes[transfer.purpose];


const call = {
type: "call",
callType: (before ? "before" : "after") + kind,
purpose: transfer.purpose,
from: from,
to: to,
input: "0x",
output: "0x",
traceAddress: [],
value: "0x" + transfer.value.toString(16),
gas: "0x0",
gasUsed: "0x0",
};

if (before) {
this.transfersBeforeEVMExecution.push(call);
} else {
this.transfersAfterEVMExecution.push(call);
}
},

// result is invoked when all the opcodes have been iterated over and returns
// the final result of the tracing.
result(ctx, db) {
const result = this.ctxToResult(ctx, db);
const filtered = this.filterNotUndefined(result);
const callSequence = this.sequence(filtered, [], filtered.valueBigInt, []).callSequence;
return this.encodeCallSequence(callSequence);
const evmCalls = this.encodeCallSequence(callSequence);
const beforeCalls = this.transfersBeforeEVMExecution;
const afterCalls = this.transfersAfterEVMExecution;
const calls = beforeCalls.concat(evmCalls).concat(afterCalls);
return calls;
},

ctxToResult(ctx, db) {
Expand Down Expand Up @@ -430,6 +479,7 @@
this.putValue(call);
this.putGas(call);
this.putGasUsed(call);
call.purpose = "general";

return call;
},
Expand Down
6 changes: 5 additions & 1 deletion apps/explorer/lib/explorer/chain/internal_transaction.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Explorer.Chain.InternalTransaction do
use Explorer.Schema

alias Explorer.Chain.{Address, Block, Data, Gas, Hash, PendingBlockOperation, Transaction, Wei}
alias Explorer.Chain.InternalTransaction.{Action, CallType, Result, Type}
alias Explorer.Chain.InternalTransaction.{Action, CallType, Purpose, Result, Type}

@typedoc """
* `block_number` - the `t:Explorer.Chain.Block.t/0` `number` that the `transaction` is collated into.
Expand Down Expand Up @@ -36,6 +36,7 @@ defmodule Explorer.Chain.InternalTransaction do
block_number: Explorer.Chain.Block.block_number() | nil,
type: Type.t(),
call_type: CallType.t() | nil,
purpose: Purpose.t() | nil,
created_contract_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
created_contract_address_hash: Hash.t() | nil,
created_contract_code: Data.t() | nil,
Expand All @@ -62,6 +63,7 @@ defmodule Explorer.Chain.InternalTransaction do
@primary_key false
schema "internal_transactions" do
field(:call_type, CallType)
field(:purpose, Purpose)
field(:created_contract_code, Data)
field(:error, :string)
field(:gas, :decimal)
Expand Down Expand Up @@ -630,6 +632,7 @@ defmodule Explorer.Chain.InternalTransaction do
defp internal_transaction_to_raw(%{type: :call} = transaction) do
%{
call_type: call_type,
purpose: purpose,
to_address_hash: to_address_hash,
from_address_hash: from_address_hash,
input: input,
Expand All @@ -640,6 +643,7 @@ defmodule Explorer.Chain.InternalTransaction do

action = %{
"callType" => call_type,
"purpose" => purpose,
"to" => to_address_hash,
"from" => from_address_hash,
"input" => input,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ defmodule Explorer.Chain.InternalTransaction.Action do
{"callType", Atom.to_string(type)}
end

defp entry_to_raw({"purpose", type}) do
{"purpose", Atom.to_string(type)}
end

defp entry_to_raw({"gas" = key, %Decimal{} = decimal}) do
value =
decimal
Expand Down
23 changes: 21 additions & 2 deletions apps/explorer/lib/explorer/chain/internal_transaction/call_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ defmodule Explorer.Chain.InternalTransaction.CallType do
when fuzzing these if the memory layout differs between the current contract and the delegated contract.
* `:staticcall`
"""
@type t :: :call | :callcode | :delegatecall | :staticcall
@type t :: :call | :callcode | :delegatecall | :staticcall | :beforetransfer | :aftertransfer | :beforemint | :aftermint | :beforeburn | :afterburn

@doc """
Casts `term` to `t:t/0`
Expand Down Expand Up @@ -48,11 +48,17 @@ defmodule Explorer.Chain.InternalTransaction.CallType do
"""
@impl Ecto.Type
@spec cast(term()) :: {:ok, t()} | :error
def cast(t) when t in ~w(call callcode delegatecall staticcall)a, do: {:ok, t}
def cast(t) when t in ~w(call callcode delegatecall staticcall beforetransfer aftertransfer beforemint aftermint beforeburn afterburn)a, do: {:ok, t}
def cast("call"), do: {:ok, :call}
def cast("callcode"), do: {:ok, :callcode}
def cast("delegatecall"), do: {:ok, :delegatecall}
def cast("staticcall"), do: {:ok, :staticcall}
def cast("beforetransfer"), do: {:ok, :beforetransfer}
def cast("aftertransfer"), do: {:ok, :aftertransfer}
def cast("beforemint"), do: {:ok, :beforemint}
def cast("aftermint"), do: {:ok, :aftermint}
def cast("beforeburn"), do: {:ok, :beforeburn}
def cast("afterburn"), do: {:ok, :afterburn}
def cast(_), do: :error

@doc """
Expand All @@ -79,6 +85,13 @@ defmodule Explorer.Chain.InternalTransaction.CallType do
def dump(:callcode), do: {:ok, "callcode"}
def dump(:delegatecall), do: {:ok, "delegatecall"}
def dump(:staticcall), do: {:ok, "staticcall"}
def dump(:beforetransfer), do: {:ok, "beforetransfer"}
def dump(:aftertransfer), do: {:ok, "aftertransfer"}
def dump(:beforemint), do: {:ok, "beforemint"}
def dump(:aftermint), do: {:ok, "aftermint"}
def dump(:beforeburn), do: {:ok, "beforeburn"}
def dump(:afterburn), do: {:ok, "afterburn"}

def dump(_), do: :error

@doc """
Expand All @@ -105,6 +118,12 @@ defmodule Explorer.Chain.InternalTransaction.CallType do
def load("callcode"), do: {:ok, :callcode}
def load("delegatecall"), do: {:ok, :delegatecall}
def load("staticcall"), do: {:ok, :staticcall}
def load("beforetransfer"), do: {:ok, :beforetransfer}
def load("aftertransfer"), do: {:ok, :aftertransfer}
def load("beforemint"), do: {:ok, :beforemint}
def load("aftermint"), do: {:ok, :aftermint}
def load("beforeburn"), do: {:ok, :beforeburn}
def load("afterburn"), do: {:ok, :afterburn}
def load(_), do: :error

@doc """
Expand Down
Loading