Merge pull request #8851 from blockscout/mf-reduce-dialyzer-ignore

Fix dialyzer and add TypedEctoSchema
pull/9315/head
nikitosing 9 months ago committed by GitHub
commit cf995975d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      .dialyzer-ignore
  2. 1
      CHANGELOG.md
  3. 2
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/stats_controller.ex
  4. 7
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex
  5. 7
      apps/block_scout_web/lib/block_scout_web/controllers/api/v2/utils_controller.ex
  6. 14
      apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex
  7. 157
      apps/block_scout_web/lib/block_scout_web/views/api/v2/transaction_view.ex
  8. 2
      apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs
  9. 8
      apps/explorer/lib/explorer/account/api/key.ex
  10. 2
      apps/explorer/lib/explorer/account/api/plan.ex
  11. 12
      apps/explorer/lib/explorer/account/custom_abi.ex
  12. 10
      apps/explorer/lib/explorer/account/identity.ex
  13. 34
      apps/explorer/lib/explorer/account/public_tags_request.ex
  14. 10
      apps/explorer/lib/explorer/account/tag_address.ex
  15. 10
      apps/explorer/lib/explorer/account/tag_transaction.ex
  16. 4
      apps/explorer/lib/explorer/account/watchlist.ex
  17. 32
      apps/explorer/lib/explorer/account/watchlist_address.ex
  18. 26
      apps/explorer/lib/explorer/account/watchlist_notification.ex
  19. 8
      apps/explorer/lib/explorer/accounts/user.ex
  20. 6
      apps/explorer/lib/explorer/accounts/user/authenticate.ex
  21. 12
      apps/explorer/lib/explorer/accounts/user/registration.ex
  22. 15
      apps/explorer/lib/explorer/accounts/user_contact.ex
  23. 13
      apps/explorer/lib/explorer/admin/administrator.ex
  24. 6
      apps/explorer/lib/explorer/application/constants.ex
  25. 6
      apps/explorer/lib/explorer/chain.ex
  26. 71
      apps/explorer/lib/explorer/chain/address.ex
  27. 15
      apps/explorer/lib/explorer/chain/address/coin_balance.ex
  28. 15
      apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex
  29. 30
      apps/explorer/lib/explorer/chain/address/current_token_balance.ex
  30. 17
      apps/explorer/lib/explorer/chain/address/name.ex
  31. 24
      apps/explorer/lib/explorer/chain/address/token_balance.ex
  32. 154
      apps/explorer/lib/explorer/chain/block.ex
  33. 13
      apps/explorer/lib/explorer/chain/block/emission_reward.ex
  34. 21
      apps/explorer/lib/explorer/chain/block/reward.ex
  35. 41
      apps/explorer/lib/explorer/chain/block/second_degree_relation.ex
  36. 38
      apps/explorer/lib/explorer/chain/bridged_token.ex
  37. 8
      apps/explorer/lib/explorer/chain/contract_method.ex
  38. 9
      apps/explorer/lib/explorer/chain/decompiled_smart_contract.ex
  39. 50
      apps/explorer/lib/explorer/chain/internal_transaction.ex
  40. 29
      apps/explorer/lib/explorer/chain/log.ex
  41. 16
      apps/explorer/lib/explorer/chain/pending_block_operation.ex
  42. 15
      apps/explorer/lib/explorer/chain/polygon_edge/deposit.ex
  43. 19
      apps/explorer/lib/explorer/chain/polygon_edge/deposit_execute.ex
  44. 27
      apps/explorer/lib/explorer/chain/polygon_edge/withdrawal.ex
  45. 17
      apps/explorer/lib/explorer/chain/polygon_edge/withdrawal_exit.ex
  46. 34
      apps/explorer/lib/explorer/chain/shibarium/bridge.ex
  47. 41
      apps/explorer/lib/explorer/chain/smart_contract.ex
  48. 35
      apps/explorer/lib/explorer/chain/smart_contract/audit_report.ex
  49. 4
      apps/explorer/lib/explorer/chain/smart_contract/external_library.ex
  50. 19
      apps/explorer/lib/explorer/chain/smart_contract/proxy/verification_status.ex
  51. 17
      apps/explorer/lib/explorer/chain/smart_contract/verification_status.ex
  52. 16
      apps/explorer/lib/explorer/chain/smart_contract_additional_source.ex
  53. 147
      apps/explorer/lib/explorer/chain/token.ex
  54. 24
      apps/explorer/lib/explorer/chain/token/instance.ex
  55. 65
      apps/explorer/lib/explorer/chain/token_transfer.ex
  56. 502
      apps/explorer/lib/explorer/chain/transaction.ex
  57. 16
      apps/explorer/lib/explorer/chain/transaction/fork.ex
  58. 19
      apps/explorer/lib/explorer/chain/transaction/history/transaction_stats.ex
  59. 27
      apps/explorer/lib/explorer/chain/transaction_action.ex
  60. 15
      apps/explorer/lib/explorer/chain/user_operation.ex
  61. 4
      apps/explorer/lib/explorer/chain/validator.ex
  62. 25
      apps/explorer/lib/explorer/chain/withdrawal.ex
  63. 22
      apps/explorer/lib/explorer/chain/zkevm/batch_transaction.ex
  64. 20
      apps/explorer/lib/explorer/chain/zkevm/lifecycle_transaction.ex
  65. 21
      apps/explorer/lib/explorer/chain/zkevm/transaction_batch.ex
  66. 10
      apps/explorer/lib/explorer/counters/last_fetched_counter.ex
  67. 2
      apps/explorer/lib/explorer/encrypted/address_hash.ex
  68. 2
      apps/explorer/lib/explorer/encrypted/binary.ex
  69. 2
      apps/explorer/lib/explorer/encrypted/transaction_hash.ex
  70. 22
      apps/explorer/lib/explorer/market/market_history.ex
  71. 2
      apps/explorer/lib/explorer/migrator/migration_status.ex
  72. 2
      apps/explorer/lib/explorer/schema.ex
  73. 10
      apps/explorer/lib/explorer/tags/address_tag.ex
  74. 13
      apps/explorer/lib/explorer/tags/address_to_tag.ex
  75. 2
      apps/explorer/lib/explorer/utility/event_notification.ex
  76. 2
      apps/explorer/lib/explorer/utility/missing_block_range.ex
  77. 3
      apps/explorer/mix.exs
  78. 1
      mix.lock

@ -1,16 +1,8 @@
:0: Unknown function 'Elixir.ExUnit.Callbacks':'__merge__'/3
:0: Unknown function 'Elixir.ExUnit.CaseTemplate':'__proxy__'/2
:0: Unknown type 'Elixir.Map':t/0
:0: Unknown type 'Elixir.Hash':t/0
:0: Unknown type 'Elixir.Address':t/0
lib/ethereum_jsonrpc/rolling_window.ex:171
lib/explorer/smart_contract/solidity/publisher_worker.ex:1
lib/explorer/smart_contract/vyper/publisher_worker.ex:1
lib/explorer/smart_contract/solidity/publisher_worker.ex:8
lib/explorer/smart_contract/vyper/publisher_worker.ex:8
lib/block_scout_web/router.ex:1
lib/block_scout_web/schema/types.ex:31
lib/phoenix/router.ex:324
lib/phoenix/router.ex:402
lib/explorer/smart_contract/reader.ex:435
lib/explorer/exchange_rates/source.ex:139

@ -11,6 +11,7 @@
### Chore
- [#9361](https://github.com/blockscout/blockscout/pull/9361) - Define BRIDGED_TOKENS_ENABLED env in Dockerfile
- [#8851](https://github.com/blockscout/blockscout/pull/8851) - Fix dialyzer and add TypedEctoSchema
<details>
<summary>Dependencies version bumps</summary>

@ -1,8 +1,6 @@
defmodule BlockScoutWeb.API.RPC.StatsController do
use BlockScoutWeb, :controller
use Explorer.Schema
alias Explorer.{Chain, Etherscan, Market}
alias Explorer.Chain.Cache.{AddressSum, AddressSumMinusBurnt}
alias Explorer.Chain.Wei

@ -196,7 +196,12 @@ defmodule BlockScoutWeb.API.V2.TokenController do
|> Chain.put_owner_to_token_instance(token, @api_true)
{:error, :not_found} ->
%Instance{token_id: token_id, metadata: nil, owner: nil}
%Instance{
token_id: Decimal.new(token_id),
metadata: nil,
owner: nil,
token_contract_address_hash: address_hash
}
|> Instance.put_is_unique(token, @api_true)
|> Chain.put_owner_to_token_instance(token, @api_true)
end

@ -3,7 +3,7 @@ defmodule BlockScoutWeb.API.V2.UtilsController do
alias BlockScoutWeb.API.V2.TransactionView
alias Explorer.Chain
alias Explorer.Chain.{Data, SmartContract, Transaction}
alias Explorer.Chain.{Address, Data, SmartContract, Transaction}
@api_true [api?: true]
@ -22,7 +22,10 @@ defmodule BlockScoutWeb.API.V2.UtilsController do
{decoded_input, _abi_acc, _methods_acc} =
Transaction.decoded_input_data(
%Transaction{input: data, to_address: %{contract_code: "", smart_contract: smart_contract}},
%Transaction{
input: data,
to_address: %Address{contract_code: %Data{bytes: ""}, smart_contract: smart_contract}
},
@api_true
)

@ -139,7 +139,8 @@ defmodule BlockScoutWeb.API.V2.AddressView do
})
end
def prepare_token_balance(token_balance, fetch_token_instance? \\ false) do
@spec prepare_token_balance(Chain.Address.TokenBalance.t(), boolean()) :: map()
defp prepare_token_balance(token_balance, fetch_token_instance? \\ false) do
%{
"value" => token_balance.value,
"token" => TokenView.render("token.json", %{token: token_balance.token}),
@ -221,6 +222,12 @@ defmodule BlockScoutWeb.API.V2.AddressView do
# TODO think about this approach mb refactor or mark deprecated for example.
# Suggested solution: batch preload
@spec fetch_and_render_token_instance(
Decimal.t(),
Ecto.Schema.belongs_to(Chain.Token.t()) | nil,
Chain.Hash.Address.t(),
Chain.Address.TokenBalance.t()
) :: map()
def fetch_and_render_token_instance(token_id, token, address_hash, token_balance) do
token_instance =
case Chain.erc721_or_erc1155_token_instance_from_token_id_and_token_address(
@ -236,8 +243,9 @@ defmodule BlockScoutWeb.API.V2.AddressView do
%Instance{
token_id: token_id,
metadata: nil,
owner: %{hash: address_hash},
current_token_balance: token_balance
owner: %Address{hash: address_hash},
current_token_balance: token_balance,
token_contract_address_hash: token.contract_address_hash
}
|> Instance.put_is_unique(token, @api_true)
end

@ -8,7 +8,7 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
alias BlockScoutWeb.TransactionStateView
alias Ecto.Association.NotLoaded
alias Explorer.{Chain, Market}
alias Explorer.Chain.{Address, Block, Hash, InternalTransaction, Log, Token, Transaction, Wei}
alias Explorer.Chain.{Address, Block, InternalTransaction, Log, Token, Transaction, Wei}
alias Explorer.Chain.Block.Reward
alias Explorer.Chain.PolygonEdge.Reader
alias Explorer.Chain.Transaction.StateChange
@ -17,10 +17,8 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
import BlockScoutWeb.Account.AuthController, only: [current_user: 1]
import Explorer.Chain.Transaction, only: [maybe_prepare_stability_fees: 1, bytes_to_address_hash: 1]
import Explorer.Helper, only: [decode_data: 2]
@api_true [api?: true]
@suave_bid_event "0x83481d5b04dea534715acad673a8177a46fc93882760f36bdc16ccac439d504e"
def render("message.json", assigns) do
ApiView.render("message.json", assigns)
@ -482,105 +480,70 @@ defmodule BlockScoutWeb.API.V2.TransactionView do
end
end
defp suave_fields(transaction, result, single_tx?, conn, watchlist_names) do
if is_nil(transaction.execution_node_hash) do
result
else
{[wrapped_decoded_input], _, _} =
decode_transactions(
[
%Transaction{
to_address: transaction.wrapped_to_address,
input: transaction.wrapped_input,
hash: transaction.wrapped_hash
}
],
false
)
if Application.compile_env(:explorer, :chain_type) != "suave" do
defp suave_fields(_transaction, result, _single_tx?, _conn, _watchlist_names), do: result
else
defp suave_fields(transaction, result, single_tx?, conn, watchlist_names) do
if is_nil(transaction.execution_node_hash) do
result
else
{[wrapped_decoded_input], _, _} =
decode_transactions(
[
%Transaction{
to_address: transaction.wrapped_to_address,
input: transaction.wrapped_input,
hash: transaction.wrapped_hash
}
],
false
)
result
|> Map.put("allowed_peekers", suave_parse_allowed_peekers(transaction.logs))
|> Map.put(
"execution_node",
Helper.address_with_info(
single_tx? && conn,
transaction.execution_node,
transaction.execution_node_hash,
single_tx?,
watchlist_names
)
)
|> Map.put("wrapped", %{
"type" => transaction.wrapped_type,
"nonce" => transaction.wrapped_nonce,
"to" =>
result
|> Map.put("allowed_peekers", Transaction.suave_parse_allowed_peekers(transaction.logs))
|> Map.put(
"execution_node",
Helper.address_with_info(
single_tx? && conn,
transaction.wrapped_to_address,
transaction.wrapped_to_address_hash,
transaction.execution_node,
transaction.execution_node_hash,
single_tx?,
watchlist_names
),
"gas_limit" => transaction.wrapped_gas,
"gas_price" => transaction.wrapped_gas_price,
"fee" =>
format_fee(
Chain.fee(
%Transaction{gas: transaction.wrapped_gas, gas_price: transaction.wrapped_gas_price, gas_used: nil},
:wei
)
),
"max_priority_fee_per_gas" => transaction.wrapped_max_priority_fee_per_gas,
"max_fee_per_gas" => transaction.wrapped_max_fee_per_gas,
"value" => transaction.wrapped_value,
"hash" => transaction.wrapped_hash,
"method" =>
method_name(
%Transaction{to_address: transaction.wrapped_to_address, input: transaction.wrapped_input},
wrapped_decoded_input
),
"decoded_input" => decoded_input(wrapped_decoded_input),
"raw_input" => transaction.wrapped_input
})
end
end
defp suave_parse_allowed_peekers(logs) do
suave_bid_contracts =
Application.get_all_env(:explorer)[Transaction][:suave_bid_contracts]
|> String.split(",")
|> Enum.map(fn sbc -> String.downcase(String.trim(sbc)) end)
bid_event =
Enum.find(logs, fn log ->
sanitize_log_first_topic(log.first_topic) == @suave_bid_event &&
Enum.member?(suave_bid_contracts, String.downcase(Hash.to_string(log.address_hash)))
end)
if is_nil(bid_event) do
[]
else
[_bid_id, _decryption_condition, allowed_peekers] =
decode_data(bid_event.data, [{:bytes, 16}, {:uint, 64}, {:array, :address}])
Enum.map(allowed_peekers, fn peeker ->
"0x" <> Base.encode16(peeker, case: :lower)
end)
end
end
defp sanitize_log_first_topic(first_topic) do
if is_nil(first_topic) do
""
else
sanitized =
if is_binary(first_topic) do
first_topic
else
Hash.to_string(first_topic)
end
String.downcase(sanitized)
)
)
|> Map.put("wrapped", %{
"type" => transaction.wrapped_type,
"nonce" => transaction.wrapped_nonce,
"to" =>
Helper.address_with_info(
single_tx? && conn,
transaction.wrapped_to_address,
transaction.wrapped_to_address_hash,
single_tx?,
watchlist_names
),
"gas_limit" => transaction.wrapped_gas,
"gas_price" => transaction.wrapped_gas_price,
"fee" =>
format_fee(
Chain.fee(
%Transaction{gas: transaction.wrapped_gas, gas_price: transaction.wrapped_gas_price, gas_used: nil},
:wei
)
),
"max_priority_fee_per_gas" => transaction.wrapped_max_priority_fee_per_gas,
"max_fee_per_gas" => transaction.wrapped_max_fee_per_gas,
"value" => transaction.wrapped_value,
"hash" => transaction.wrapped_hash,
"method" =>
method_name(
%Transaction{to_address: transaction.wrapped_to_address, input: transaction.wrapped_input},
wrapped_decoded_input
),
"decoded_input" => decoded_input(wrapped_decoded_input),
"raw_input" => transaction.wrapped_input
})
end
end
end

@ -1022,7 +1022,7 @@ defmodule BlockScoutWeb.API.V2.TokenControllerTest do
assert %{
"animation_url" => nil,
"external_app_url" => nil,
"id" => 0,
"id" => "0",
"image_url" => nil,
"is_unique" => true,
"metadata" => nil,

@ -13,10 +13,10 @@ defmodule Explorer.Account.Api.Key do
@max_key_per_account 3
@primary_key false
schema "account_api_keys" do
field(:name, :string)
field(:value, UUID, primary_key: true)
belongs_to(:identity, Identity)
typed_schema "account_api_keys" do
field(:name, :string, null: false)
field(:value, UUID, primary_key: true, null: false)
belongs_to(:identity, Identity, null: false)
timestamps()
end

@ -4,7 +4,7 @@ defmodule Explorer.Account.Api.Plan do
"""
use Explorer.Schema
schema "account_api_plans" do
typed_schema "account_api_plans" do
field(:name, :string)
field(:max_req_per_second, :integer)

@ -14,15 +14,15 @@ defmodule Explorer.Account.CustomABI do
@max_abis_per_account 15
schema "account_custom_abis" do
field(:abi, {:array, :map})
typed_schema "account_custom_abis" do
field(:abi, {:array, :map}, null: false)
field(:given_abi, :string, virtual: true)
field(:abi_validating_error, :string, virtual: true)
field(:address_hash_hash, Cloak.Ecto.SHA256)
field(:address_hash, Explorer.Encrypted.AddressHash)
field(:name, Explorer.Encrypted.Binary)
field(:address_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:address_hash, Explorer.Encrypted.AddressHash, null: false)
field(:name, Explorer.Encrypted.Binary, null: false)
belongs_to(:identity, Identity)
belongs_to(:identity, Identity, null: false)
timestamps()
end

@ -10,11 +10,11 @@ defmodule Explorer.Account.Identity do
alias Explorer.Account.Api.Plan
alias Explorer.Account.{TagAddress, Watchlist}
schema "account_identities" do
field(:uid_hash, Cloak.Ecto.SHA256)
field(:uid, Explorer.Encrypted.Binary)
field(:email, Explorer.Encrypted.Binary)
field(:name, Explorer.Encrypted.Binary)
typed_schema "account_identities" do
field(:uid_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:uid, Explorer.Encrypted.Binary, null: false)
field(:email, Explorer.Encrypted.Binary, null: false)
field(:name, Explorer.Encrypted.Binary, null: false)
field(:nickname, Explorer.Encrypted.Binary)
field(:avatar, Explorer.Encrypted.Binary)
field(:verification_email_sent_at, :utc_datetime_usec)

@ -19,37 +19,21 @@ defmodule Explorer.Account.PublicTagsRequest do
@max_tags_per_request 2
@max_tag_length 35
@type t :: %__MODULE__{
company: String.t(),
website: String.t(),
tags: String.t(),
addresses: [Hash.Address.t()],
description: String.t(),
additional_comment: String.t(),
request_type: String.t(),
is_owner: boolean(),
remove_reason: String.t(),
request_id: String.t(),
full_name: String.t(),
email: String.t(),
identity_id: integer()
}
schema("account_public_tags_requests") do
typed_schema "account_public_tags_requests" do
field(:company, :string)
field(:website, :string)
field(:tags, :string)
field(:addresses, {:array, Hash.Address})
field(:tags, :string, null: false)
field(:addresses, {:array, Hash.Address}, null: false)
field(:description, :string)
field(:additional_comment, :string)
field(:request_type, :string)
field(:is_owner, :boolean, default: true)
field(:additional_comment, :string, null: false)
field(:request_type, :string, null: false)
field(:is_owner, :boolean, default: true, null: false)
field(:remove_reason, :string)
field(:request_id, :string)
field(:full_name, Explorer.Encrypted.Binary)
field(:email, Explorer.Encrypted.Binary)
field(:full_name, Explorer.Encrypted.Binary, null: false)
field(:email, Explorer.Encrypted.Binary, null: false)
belongs_to(:identity, Identity)
belongs_to(:identity, Identity, null: false)
timestamps()
end

@ -14,12 +14,12 @@ defmodule Explorer.Account.TagAddress do
import Explorer.Chain, only: [hash_to_lower_case_string: 1]
schema "account_tag_addresses" do
field(:address_hash_hash, Cloak.Ecto.SHA256)
field(:name, Explorer.Encrypted.Binary)
field(:address_hash, Explorer.Encrypted.AddressHash)
typed_schema "account_tag_addresses" do
field(:address_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:name, Explorer.Encrypted.Binary, null: false)
field(:address_hash, Explorer.Encrypted.AddressHash, null: false)
belongs_to(:identity, Identity)
belongs_to(:identity, Identity, null: false)
timestamps()
end

@ -12,12 +12,12 @@ defmodule Explorer.Account.TagTransaction do
alias Explorer.{Chain, PagingOptions, Repo}
import Explorer.Chain, only: [hash_to_lower_case_string: 1]
schema "account_tag_transactions" do
field(:tx_hash_hash, Cloak.Ecto.SHA256)
field(:name, Explorer.Encrypted.Binary)
field(:tx_hash, Explorer.Encrypted.TransactionHash)
typed_schema "account_tag_transactions" do
field(:tx_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:name, Explorer.Encrypted.Binary, null: false)
field(:tx_hash, Explorer.Encrypted.TransactionHash, null: false)
belongs_to(:identity, Identity)
belongs_to(:identity, Identity, null: false)
timestamps()
end

@ -10,8 +10,8 @@ defmodule Explorer.Account.Watchlist do
alias Explorer.Account.{Identity, WatchlistAddress}
@derive {Jason.Encoder, only: [:name, :watchlist_addresses]}
schema "account_watchlists" do
field(:name, :string)
typed_schema "account_watchlists" do
field(:name, :string, null: false)
belongs_to(:identity, Identity)
has_many(:watchlist_addresses, WatchlistAddress)

@ -15,22 +15,22 @@ defmodule Explorer.Account.WatchlistAddress do
import Explorer.Chain, only: [hash_to_lower_case_string: 1]
schema "account_watchlist_addresses" do
field(:address_hash_hash, Cloak.Ecto.SHA256)
field(:name, Explorer.Encrypted.Binary)
field(:address_hash, Explorer.Encrypted.AddressHash)
belongs_to(:watchlist, Watchlist)
field(:watch_coin_input, :boolean, default: true)
field(:watch_coin_output, :boolean, default: true)
field(:watch_erc_20_input, :boolean, default: true)
field(:watch_erc_20_output, :boolean, default: true)
field(:watch_erc_721_input, :boolean, default: true)
field(:watch_erc_721_output, :boolean, default: true)
field(:watch_erc_1155_input, :boolean, default: true)
field(:watch_erc_1155_output, :boolean, default: true)
field(:notify_email, :boolean, default: true)
typed_schema "account_watchlist_addresses" do
field(:address_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:name, Explorer.Encrypted.Binary, null: false)
field(:address_hash, Explorer.Encrypted.AddressHash, null: false)
belongs_to(:watchlist, Watchlist, null: false)
field(:watch_coin_input, :boolean, default: true, null: false)
field(:watch_coin_output, :boolean, default: true, null: false)
field(:watch_erc_20_input, :boolean, default: true, null: false)
field(:watch_erc_20_output, :boolean, default: true, null: false)
field(:watch_erc_721_input, :boolean, default: true, null: false)
field(:watch_erc_721_output, :boolean, default: true, null: false)
field(:watch_erc_1155_input, :boolean, default: true, null: false)
field(:watch_erc_1155_output, :boolean, default: true, null: false)
field(:notify_email, :boolean, default: true, null: false)
field(:notify_epns, :boolean)
field(:notify_feed, :boolean)
field(:notify_inapp, :boolean)

@ -12,17 +12,17 @@ defmodule Explorer.Account.WatchlistNotification do
alias Explorer.Repo
alias Explorer.Account.{Watchlist, WatchlistAddress}
schema "account_watchlist_notifications" do
field(:amount, :decimal)
field(:block_number, :integer)
field(:direction, :string)
field(:method, :string)
field(:tx_fee, :decimal)
field(:type, :string)
field(:viewed_at, :integer)
field(:name, Explorer.Encrypted.Binary)
typed_schema "account_watchlist_notifications" do
field(:amount, :decimal, null: false)
field(:block_number, :integer, null: false)
field(:direction, :string, null: false)
field(:method, :string, null: false)
field(:tx_fee, :decimal, null: false)
field(:type, :string, null: false)
field(:viewed_at, :integer, null: false)
field(:name, Explorer.Encrypted.Binary, null: false)
field(:subject, Explorer.Encrypted.Binary)
field(:subject_hash, Cloak.Ecto.SHA256)
field(:subject_hash, Cloak.Ecto.SHA256) :: binary() | nil
belongs_to(:watchlist_address, WatchlistAddress)
belongs_to(:watchlist, Watchlist)
@ -31,9 +31,9 @@ defmodule Explorer.Account.WatchlistNotification do
field(:to_address_hash, Explorer.Encrypted.AddressHash)
field(:transaction_hash, Explorer.Encrypted.TransactionHash)
field(:from_address_hash_hash, Cloak.Ecto.SHA256)
field(:to_address_hash_hash, Cloak.Ecto.SHA256)
field(:transaction_hash_hash, Cloak.Ecto.SHA256)
field(:from_address_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:to_address_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
field(:transaction_hash_hash, Cloak.Ecto.SHA256) :: binary() | nil
timestamps()
end

@ -16,13 +16,7 @@ defmodule Explorer.Accounts.User do
* `:password_hash` - Encrypted password
* `:contacts` - List of `t:UserContact.t/0`
"""
@type t :: %User{
username: String.t(),
password_hash: String.t(),
contacts: [UserContact.t()]
}
schema "users" do
typed_schema "users" do
field(:username, :string)
field(:password, :string, virtual: true)
field(:password_hash, :string)

@ -7,9 +7,9 @@ defmodule Explorer.Accounts.User.Authenticate do
import Ecto.Changeset
embedded_schema do
field(:username, :string)
field(:password, :string)
typed_embedded_schema do
field(:username, :string, null: false)
field(:password, :string, null: false)
end
@required_attrs ~w(password username)a

@ -9,13 +9,11 @@ defmodule Explorer.Accounts.User.Registration do
alias Explorer.Accounts.User.Registration
@type t :: %__MODULE__{}
embedded_schema do
field(:username, :string)
field(:email, :string)
field(:password, :string)
field(:password_confirmation, :string)
typed_embedded_schema do
field(:username, :string, null: false)
field(:email, :string, null: false)
field(:password, :string, null: false)
field(:password_confirmation, :string, null: false)
end
@fields ~w(email password password_confirmation username)a

@ -19,17 +19,10 @@ defmodule Explorer.Accounts.UserContact do
* `:verified` - Flag indicating if email contact has been verified
* `:user` - owning `t:User.t/0`
"""
@type t :: %UserContact{
email: String.t(),
primary: boolean(),
verified: boolean(),
user: User.t()
}
schema "user_contacts" do
field(:email, :string)
field(:primary, :boolean, default: false)
field(:verified, :boolean, default: false)
typed_schema "user_contacts" do
field(:email, :string, null: false)
field(:primary, :boolean, default: false, null: false)
field(:verified, :boolean, default: false, null: false)
belongs_to(:user, User)

@ -8,22 +8,15 @@ defmodule Explorer.Admin.Administrator do
import Ecto.Changeset
alias Explorer.Accounts.User
alias Explorer.Admin.Administrator
alias Explorer.Admin.Administrator.Role
@typedoc """
* `:role` - Administrator's role determining permission level
* `:user` - The `t:User.t/0` that is an admin
* `:user_id` - User foreign key
"""
@type t :: %Administrator{
role: Role.t(),
user: User.t() | %Ecto.Association.NotLoaded{}
}
schema "administrators" do
field(:role, :string)
belongs_to(:user, User)
typed_schema "administrators" do
field(:role, :string, null: false)
belongs_to(:user, User, null: false)
timestamps()
end

@ -9,9 +9,9 @@ defmodule Explorer.Application.Constants do
@keys_manager_contract_address_key "keys_manager_contract_address"
@primary_key false
schema "constants" do
field(:key, :string, primary_key: true)
field(:value, :string)
typed_schema "constants" do
field(:key, :string, primary_key: true, null: false)
field(:value, :string, null: false)
timestamps()
end

@ -3833,7 +3833,11 @@ defmodule Explorer.Chain do
|> select_repo(options).all()
end
@spec erc721_or_erc1155_token_instance_from_token_id_and_token_address(non_neg_integer(), Hash.Address.t(), [api?]) ::
@spec erc721_or_erc1155_token_instance_from_token_id_and_token_address(
Decimal.t() | non_neg_integer(),
Hash.Address.t(),
[api?]
) ::
{:ok, Instance.t()} | {:error, :not_found}
def erc721_or_erc1155_token_instance_from_token_id_and_token_address(token_id, token_contract_address, options \\ []) do
query = Instance.token_instance_query(token_id, token_contract_address)

@ -36,38 +36,6 @@ defmodule Explorer.Chain.Address do
"""
@type hash :: Hash.t()
@typedoc """
* `fetched_coin_balance` - The last fetched balance from Nethermind
* `fetched_coin_balance_block_number` - the `t:Explorer.Chain.Block.t/0` `t:Explorer.Chain.Block.block_number/0` for
which `fetched_coin_balance` was fetched
* `hash` - the hash of the address's public key
* `contract_code` - the binary code of the contract when an Address is a contract. The human-readable
Solidity source code is in `smart_contract` `t:Explorer.Chain.SmartContract.t/0` `contract_source_code` *if* the
contract has been verified
* `names` - names known for the address
* `inserted_at` - when this address was inserted
* `updated_at` - when this address was last updated
* `ens_domain_name` - virtual field for ENS domain name passing
`fetched_coin_balance` and `fetched_coin_balance_block_number` may be updated when a new coin_balance row is fetched.
They may also be updated when the balance is fetched via the on demand fetcher.
"""
@type t :: %__MODULE__{
fetched_coin_balance: Wei.t(),
fetched_coin_balance_block_number: Block.block_number(),
hash: Hash.Address.t(),
contract_code: Data.t() | nil,
names: %Ecto.Association.NotLoaded{} | [Address.Name.t()],
contracts_creation_transaction: %Ecto.Association.NotLoaded{} | Transaction.t(),
inserted_at: DateTime.t(),
updated_at: DateTime.t(),
nonce: non_neg_integer() | nil,
transactions_count: non_neg_integer() | nil,
token_transfers_count: non_neg_integer() | nil,
gas_used: non_neg_integer() | nil,
ens_domain_name: String.t() | nil
}
@derive {Poison.Encoder,
except: [
:__meta__,
@ -90,10 +58,27 @@ defmodule Explorer.Chain.Address do
:names
]}
@primary_key {:hash, Hash.Address, autogenerate: false}
schema "addresses" do
@typedoc """
* `fetched_coin_balance` - The last fetched balance from Nethermind
* `fetched_coin_balance_block_number` - the `t:Explorer.Chain.Block.t/0` `t:Explorer.Chain.Block.block_number/0` for
which `fetched_coin_balance` was fetched
* `hash` - the hash of the address's public key
* `contract_code` - the binary code of the contract when an Address is a contract. The human-readable
Solidity source code is in `smart_contract` `t:Explorer.Chain.SmartContract.t/0` `contract_source_code` *if* the
contract has been verified
* `names` - names known for the address
* `inserted_at` - when this address was inserted
* `updated_at` - when this address was last updated
* `ens_domain_name` - virtual field for ENS domain name passing
`fetched_coin_balance` and `fetched_coin_balance_block_number` may be updated when a new coin_balance row is fetched.
They may also be updated when the balance is fetched via the on demand fetcher.
"""
@primary_key false
typed_schema "addresses" do
field(:hash, Hash.Address, primary_key: true)
field(:fetched_coin_balance, Wei)
field(:fetched_coin_balance_block_number, :integer)
field(:fetched_coin_balance_block_number, :integer) :: Block.block_number() | nil
field(:contract_code, Data)
field(:nonce, :integer)
field(:decompiled, :boolean, default: false)
@ -105,24 +90,26 @@ defmodule Explorer.Chain.Address do
field(:gas_used, :integer)
field(:ens_domain_name, :string, virtual: true)
has_one(:smart_contract, SmartContract)
has_one(:token, Token, foreign_key: :contract_address_hash)
has_one(:smart_contract, SmartContract, references: :hash)
has_one(:token, Token, foreign_key: :contract_address_hash, references: :hash)
has_one(
:contracts_creation_internal_transaction,
InternalTransaction,
foreign_key: :created_contract_address_hash
foreign_key: :created_contract_address_hash,
references: :hash
)
has_one(
:contracts_creation_transaction,
Transaction,
foreign_key: :created_contract_address_hash
foreign_key: :created_contract_address_hash,
references: :hash
)
has_many(:names, Address.Name, foreign_key: :address_hash)
has_many(:decompiled_smart_contracts, DecompiledSmartContract, foreign_key: :address_hash)
has_many(:withdrawals, Withdrawal, foreign_key: :address_hash)
has_many(:names, Address.Name, foreign_key: :address_hash, references: :hash)
has_many(:decompiled_smart_contracts, DecompiledSmartContract, foreign_key: :address_hash, references: :hash)
has_many(:withdrawals, Withdrawal, foreign_key: :address_hash, references: :hash)
timestamps()
end

@ -27,18 +27,9 @@ defmodule Explorer.Chain.Address.CoinBalance do
given `address`, the `t:Explorer.Chain.Address.t/0` `fetched_coin_balance` will match this value.
* `value_fetched_at` - when `value` was fetched.
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t(),
block_number: Block.block_number(),
inserted_at: DateTime.t(),
updated_at: DateTime.t(),
value: Wei.t() | nil
}
@primary_key false
schema "address_coin_balances" do
field(:block_number, :integer)
typed_schema "address_coin_balances" do
field(:block_number, :integer) :: Block.block_number()
field(:value, Wei)
field(:value_fetched_at, :utc_datetime_usec)
field(:delta, Wei, virtual: true)
@ -47,7 +38,7 @@ defmodule Explorer.Chain.Address.CoinBalance do
timestamps()
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address, null: false)
end
@doc """

@ -21,23 +21,14 @@ defmodule Explorer.Chain.Address.CoinBalanceDaily do
* `updated_at` - When the balance was last updated.
* `value` - the max balance (`value`) of `address` during the `day`.
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t(),
day: Date.t(),
inserted_at: DateTime.t(),
updated_at: DateTime.t(),
value: Wei.t() | nil
}
@primary_key false
schema "address_coin_balances_daily" do
field(:day, :date)
typed_schema "address_coin_balances_daily" do
field(:day, :date, null: false)
field(:value, Wei)
timestamps()
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address, null: false)
end
@doc """

@ -27,30 +27,13 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
* `token_id` - The token_id of the transferred token (applicable for ERC-1155)
* `token_type` - The type of the token
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t(),
token: %Ecto.Association.NotLoaded{} | Token.t(),
token_contract_address_hash: Hash.Address,
block_number: Block.block_number(),
max_block_number: Block.block_number(),
inserted_at: DateTime.t(),
updated_at: DateTime.t(),
value: Decimal.t() | nil,
token_id: non_neg_integer() | nil,
token_type: String.t(),
distinct_token_instances_count: non_neg_integer(),
token_ids: list(Decimal.t()),
preloaded_token_instances: list()
}
schema "address_current_token_balances" do
typed_schema "address_current_token_balances" do
field(:value, :decimal)
field(:block_number, :integer)
field(:max_block_number, :integer, virtual: true)
field(:block_number, :integer) :: Block.block_number()
field(:max_block_number, :integer, virtual: true) :: Block.block_number()
field(:value_fetched_at, :utc_datetime_usec)
field(:token_id, :decimal)
field(:token_type, :string)
field(:token_type, :string, null: false)
field(:fiat_value, :decimal, virtual: true)
field(:distinct_token_instances_count, :integer, virtual: true)
field(:token_ids, {:array, :decimal}, virtual: true)
@ -59,14 +42,15 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
# A transient field for deriving token holder count deltas during address_current_token_balances upserts
field(:old_value, :decimal)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address, null: false)
belongs_to(
:token,
Token,
foreign_key: :token_contract_address_hash,
references: :contract_address_hash,
type: Hash.Address
type: Hash.Address,
null: false
)
timestamps()

@ -18,20 +18,13 @@ defmodule Explorer.Chain.Address.Name do
* `name` - name for the address
* `primary` - flag for if the name is the primary name for the address
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t(),
name: String.t(),
primary: boolean(),
metadata: map()
}
@primary_key {:id, :integer, autogenerate: false}
schema "address_names" do
field(:name, :string)
@primary_key false
typed_schema "address_names" do
field(:id, :integer, autogenerate: false, primary_key: true, null: false)
field(:name, :string, null: false)
field(:primary, :boolean)
field(:metadata, :map)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address, null: false)
timestamps()
end

@ -26,34 +26,22 @@ defmodule Explorer.Chain.Address.TokenBalance do
* `token_id` - The token_id of the transferred token (applicable for ERC-1155 and ERC-721 tokens)
* `token_type` - The type of the token
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t(),
token: %Ecto.Association.NotLoaded{} | Token.t(),
token_contract_address_hash: Hash.Address,
block_number: Block.block_number(),
inserted_at: DateTime.t(),
updated_at: DateTime.t(),
value: Decimal.t() | nil,
token_id: non_neg_integer() | nil,
token_type: String.t()
}
schema "address_token_balances" do
typed_schema "address_token_balances" do
field(:value, :decimal)
field(:block_number, :integer)
field(:block_number, :integer) :: Block.block_number()
field(:value_fetched_at, :utc_datetime_usec)
field(:token_id, :decimal)
field(:token_type, :string)
field(:token_type, :string, null: false)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address, null: false)
belongs_to(
:token,
Token,
foreign_key: :token_contract_address_hash,
references: :contract_address_hash,
type: Hash.Address
type: Hash.Address,
null: false
)
timestamps()

@ -1,3 +1,71 @@
defmodule Explorer.Chain.Block.Schema do
@moduledoc false
alias Explorer.Chain.{Address, Block, Hash, PendingBlockOperation, Transaction, Wei, Withdrawal}
alias Explorer.Chain.Block.{Reward, SecondDegreeRelation}
@chain_type_fields (case Application.compile_env(:explorer, :chain_type) do
"rsk" ->
elem(
quote do
field(:bitcoin_merged_mining_header, :binary)
field(:bitcoin_merged_mining_coinbase_transaction, :binary)
field(:bitcoin_merged_mining_merkle_proof, :binary)
field(:hash_for_merged_mining, :binary)
field(:minimum_gas_price, :decimal)
end,
2
)
_ ->
[]
end)
defmacro generate do
quote do
@primary_key false
typed_schema "blocks" do
field(:hash, Hash.Full, primary_key: true, null: false)
field(:consensus, :boolean, null: false)
field(:difficulty, :decimal)
field(:gas_limit, :decimal, null: false)
field(:gas_used, :decimal, null: false)
field(:nonce, Hash.Nonce, null: false)
field(:number, :integer, null: false)
field(:size, :integer)
field(:timestamp, :utc_datetime_usec, null: false)
field(:total_difficulty, :decimal)
field(:refetch_needed, :boolean)
field(:base_fee_per_gas, Wei)
field(:is_empty, :boolean)
timestamps()
belongs_to(:miner, Address, foreign_key: :miner_hash, references: :hash, type: Hash.Address, null: false)
has_many(:nephew_relations, SecondDegreeRelation, foreign_key: :uncle_hash, references: :hash)
has_many(:nephews, through: [:nephew_relations, :nephew], references: :hash)
belongs_to(:parent, Block, foreign_key: :parent_hash, references: :hash, type: Hash.Full, null: false)
has_many(:uncle_relations, SecondDegreeRelation, foreign_key: :nephew_hash, references: :hash)
has_many(:uncles, through: [:uncle_relations, :uncle], references: :hash)
has_many(:transactions, Transaction, references: :hash)
has_many(:transaction_forks, Transaction.Fork, foreign_key: :uncle_hash, references: :hash)
has_many(:rewards, Reward, foreign_key: :block_hash, references: :hash)
has_many(:withdrawals, Withdrawal, foreign_key: :block_hash, references: :hash)
has_one(:pending_operations, PendingBlockOperation, foreign_key: :block_hash, references: :hash)
unquote_splicing(@chain_type_fields)
end
end
end
end
defmodule Explorer.Chain.Block do
@moduledoc """
A package of data that contains zero or more transactions, the hash of the previous block ("parent"), and optionally
@ -5,10 +73,12 @@ defmodule Explorer.Chain.Block do
structure that they form is called a "blockchain".
"""
require Explorer.Chain.Block.Schema
use Explorer.Schema
alias Explorer.Chain.{Address, Block, Gas, Hash, PendingBlockOperation, Transaction, Wei, Withdrawal}
alias Explorer.Chain.Block.{EmissionReward, Reward, SecondDegreeRelation}
alias Explorer.Chain.{Block, Hash, Transaction, Wei}
alias Explorer.Chain.Block.{EmissionReward, Reward}
alias Explorer.Repo
@optional_attrs ~w(size refetch_needed total_difficulty difficulty base_fee_per_gas)a
@ -35,20 +105,6 @@ defmodule Explorer.Chain.Block do
"""
@type block_number :: non_neg_integer()
if Application.compile_env(:explorer, :chain_type) == "rsk" do
@rootstock_fields quote(
do: [
bitcoin_merged_mining_header: binary(),
bitcoin_merged_mining_coinbase_transaction: binary(),
bitcoin_merged_mining_merkle_proof: binary(),
hash_for_merged_mining: binary(),
minimum_gas_price: Decimal.t()
]
)
else
@rootstock_fields quote(do: [])
end
@typedoc """
* `consensus`
* `true` - this is a block on the longest consensus agreed upon chain.
@ -80,71 +136,7 @@ defmodule Explorer.Chain.Block do
"""
end}
"""
@type t :: %__MODULE__{
unquote_splicing(@rootstock_fields),
consensus: boolean(),
difficulty: difficulty(),
gas_limit: Gas.t(),
gas_used: Gas.t(),
hash: Hash.Full.t(),
miner: %Ecto.Association.NotLoaded{} | Address.t(),
miner_hash: Hash.Address.t(),
nonce: Hash.Nonce.t(),
number: block_number(),
parent_hash: Hash.t(),
size: non_neg_integer(),
timestamp: DateTime.t(),
total_difficulty: difficulty(),
transactions: %Ecto.Association.NotLoaded{} | [Transaction.t()],
refetch_needed: boolean(),
base_fee_per_gas: Wei.t(),
is_empty: boolean()
}
@primary_key {:hash, Hash.Full, autogenerate: false}
schema "blocks" do
field(:consensus, :boolean)
field(:difficulty, :decimal)
field(:gas_limit, :decimal)
field(:gas_used, :decimal)
field(:nonce, Hash.Nonce)
field(:number, :integer)
field(:size, :integer)
field(:timestamp, :utc_datetime_usec)
field(:total_difficulty, :decimal)
field(:refetch_needed, :boolean)
field(:base_fee_per_gas, Wei)
field(:is_empty, :boolean)
if Application.compile_env(:explorer, :chain_type) == "rsk" do
field(:bitcoin_merged_mining_header, :binary)
field(:bitcoin_merged_mining_coinbase_transaction, :binary)
field(:bitcoin_merged_mining_merkle_proof, :binary)
field(:hash_for_merged_mining, :binary)
field(:minimum_gas_price, :decimal)
end
timestamps()
belongs_to(:miner, Address, foreign_key: :miner_hash, references: :hash, type: Hash.Address)
has_many(:nephew_relations, SecondDegreeRelation, foreign_key: :uncle_hash)
has_many(:nephews, through: [:nephew_relations, :nephew])
belongs_to(:parent, __MODULE__, foreign_key: :parent_hash, references: :hash, type: Hash.Full)
has_many(:uncle_relations, SecondDegreeRelation, foreign_key: :nephew_hash)
has_many(:uncles, through: [:uncle_relations, :uncle])
has_many(:transactions, Transaction)
has_many(:transaction_forks, Transaction.Fork, foreign_key: :uncle_hash)
has_many(:rewards, Reward, foreign_key: :block_hash)
has_many(:withdrawals, Withdrawal, foreign_key: :block_hash)
has_one(:pending_operations, PendingBlockOperation, foreign_key: :block_hash)
end
Explorer.Chain.Block.Schema.generate()
def changeset(%__MODULE__{} = block, attrs) do
block

@ -5,7 +5,7 @@ defmodule Explorer.Chain.Block.EmissionReward do
use Explorer.Schema
alias Explorer.Chain.Block.{EmissionReward, Range}
alias Explorer.Chain.Block.Range
alias Explorer.Chain.Wei
@typedoc """
@ -14,15 +14,10 @@ defmodule Explorer.Chain.Block.EmissionReward do
* `:block_range` - Range of block numbers
* `:reward` - Reward given in Wei
"""
@type t :: %EmissionReward{
block_range: Range.t(),
reward: Wei.t()
}
@primary_key false
schema "emission_rewards" do
field(:block_range, Range)
field(:reward, Wei)
typed_schema "emission_rewards" do
field(:block_range, Range, null: false)
field(:reward, Wei, null: false)
end
def changeset(%__MODULE__{} = emission_reward, attrs) do

@ -43,26 +43,18 @@ defmodule Explorer.Chain.Block.Reward do
* `:block_hash` - Hash of the validated block
* `:reward` - Total block reward
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
address_hash: Hash.Address.t(),
address_type: AddressType.t(),
block: %Ecto.Association.NotLoaded{} | Block.t() | nil,
block_hash: Hash.Full.t(),
reward: Wei.t()
}
@primary_key false
schema "block_rewards" do
field(:address_type, AddressType)
field(:reward, Wei)
typed_schema "block_rewards" do
field(:address_type, AddressType, null: false)
field(:reward, Wei, null: false)
belongs_to(
:address,
Address,
foreign_key: :address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
belongs_to(
@ -70,7 +62,8 @@ defmodule Explorer.Chain.Block.Reward do
Block,
foreign_key: :block_hash,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
timestamps()

@ -29,31 +29,26 @@ defmodule Explorer.Chain.Block.SecondDegreeRelation do
* `uncle_hash` - foreign key for `uncle`.
* `index` - index of the uncle within its nephew. Can be `nil` for blocks fetched before this field was added.
"""
@type t ::
%__MODULE__{
nephew: %Ecto.Association.NotLoaded{} | Block.t(),
nephew_hash: Hash.Full.t(),
uncle: %Ecto.Association.NotLoaded{} | Block.t() | nil,
uncle_fetched_at: nil,
uncle_hash: Hash.Full.t(),
index: non_neg_integer() | nil
}
| %__MODULE__{
nephew: %Ecto.Association.NotLoaded{} | Block.t(),
nephew_hash: Hash.Full.t(),
uncle: %Ecto.Association.NotLoaded{} | Block.t(),
uncle_fetched_at: DateTime.t(),
uncle_hash: Hash.Full.t(),
index: non_neg_integer() | nil
}
@primary_key false
schema "block_second_degree_relations" do
typed_schema "block_second_degree_relations" do
field(:uncle_fetched_at, :utc_datetime_usec)
field(:index, :integer)
belongs_to(:nephew, Block, foreign_key: :nephew_hash, primary_key: true, references: :hash, type: Hash.Full)
belongs_to(:uncle, Block, foreign_key: :uncle_hash, primary_key: true, references: :hash, type: Hash.Full)
field(:index, :integer, null: true)
belongs_to(:nephew, Block,
foreign_key: :nephew_hash,
primary_key: true,
references: :hash,
type: Hash.Full,
null: false
)
belongs_to(:uncle, Block,
foreign_key: :uncle_hash,
primary_key: true,
references: :hash,
type: Hash.Full,
null: false
)
end
def changeset(%__MODULE__{} = uncle, params) do

@ -20,7 +20,6 @@ defmodule Explorer.Chain.BridgedToken do
alias Explorer.{Chain, PagingOptions, Repo, SortingHelper}
alias Explorer.Chain.{
Address,
BridgedToken,
Hash,
InternalTransaction,
@ -33,28 +32,6 @@ defmodule Explorer.Chain.BridgedToken do
@default_paging_options %PagingOptions{page_size: 50}
@typedoc """
* `foreign_chain_id` - chain ID of a foreign token
* `foreign_token_contract_address_hash` - Foreign token's contract hash
* `home_token_contract_address` - The `t:Address.t/0` of the home token's contract
* `home_token_contract_address_hash` - Home token's contract hash foreign key
* `custom_metadata` - Arbitrary string with custom metadata. For instance, tokens/weights for Balance tokens
* `custom_cap` - Custom capitalization for this token
* `lp_token` - Boolean flag: LP token or not
* `type` - omni/amb
"""
@type t :: %BridgedToken{
foreign_chain_id: Decimal.t(),
foreign_token_contract_address_hash: Hash.Address.t(),
home_token_contract_address: %Ecto.Association.NotLoaded{} | Address.t(),
home_token_contract_address_hash: Hash.Address.t(),
custom_metadata: String.t(),
custom_cap: Decimal.t(),
lp_token: boolean(),
type: String.t(),
exchange_rate: Decimal.t()
}
@derive {Poison.Encoder,
except: [
:__meta__,
@ -71,8 +48,18 @@ defmodule Explorer.Chain.BridgedToken do
:updated_at
]}
@typedoc """
* `foreign_chain_id` - chain ID of a foreign token
* `foreign_token_contract_address_hash` - Foreign token's contract hash
* `home_token_contract_address` - The `t:Address.t/0` of the home token's contract
* `home_token_contract_address_hash` - Home token's contract hash foreign key
* `custom_metadata` - Arbitrary string with custom metadata. For instance, tokens/weights for Balance tokens
* `custom_cap` - Custom capitalization for this token
* `lp_token` - Boolean flag: LP token or not
* `type` - omni/amb
"""
@primary_key false
schema "bridged_tokens" do
typed_schema "bridged_tokens" do
field(:foreign_chain_id, :decimal)
field(:foreign_token_contract_address_hash, Hash.Address)
field(:custom_metadata, :string)
@ -87,7 +74,8 @@ defmodule Explorer.Chain.BridgedToken do
foreign_key: :home_token_contract_address_hash,
primary_key: true,
references: :contract_address_hash,
type: Hash.Address
type: Hash.Address,
null: false
)
timestamps()

@ -11,13 +11,7 @@ defmodule Explorer.Chain.ContractMethod do
alias Explorer.Chain.{Hash, MethodIdentifier, SmartContract}
alias Explorer.Repo
@type t :: %__MODULE__{
identifier: MethodIdentifier.t(),
abi: map(),
type: String.t()
}
schema "contract_methods" do
typed_schema "contract_methods" do
field(:identifier, MethodIdentifier)
field(:abi, :map)
field(:type, :string)

@ -9,16 +9,17 @@ defmodule Explorer.Chain.DecompiledSmartContract do
@derive {Jason.Encoder, only: [:address_hash, :decompiler_version, :decompiled_source_code]}
schema "decompiled_smart_contracts" do
field(:decompiler_version, :string)
field(:decompiled_source_code, :string)
typed_schema "decompiled_smart_contracts" do
field(:decompiler_version, :string, null: false)
field(:decompiled_source_code, :string, null: false)
belongs_to(
:address,
Address,
foreign_key: :address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
timestamps()

@ -3,7 +3,7 @@ defmodule Explorer.Chain.InternalTransaction do
use Explorer.Schema
alias Explorer.Chain.{Address, Block, Data, Gas, Hash, PendingBlockOperation, Transaction, Wei}
alias Explorer.Chain.{Address, Block, Data, Hash, PendingBlockOperation, Transaction, Wei}
alias Explorer.Chain.InternalTransaction.{Action, CallType, Result, Type}
@typedoc """
@ -32,50 +32,23 @@ defmodule Explorer.Chain.InternalTransaction do
* `block_index` - the index of this internal transaction inside the `block`
* `pending_block` - `nil` if `block` has all its internal transactions fetched
"""
@type t :: %__MODULE__{
block_number: Explorer.Chain.Block.block_number() | nil,
type: Type.t(),
call_type: CallType.t() | nil,
created_contract_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
created_contract_address_hash: Hash.t() | nil,
created_contract_code: Data.t() | nil,
error: String.t(),
from_address: %Ecto.Association.NotLoaded{} | Address.t(),
from_address_hash: Hash.Address.t(),
gas: Gas.t() | nil,
gas_used: Gas.t() | nil,
index: non_neg_integer(),
init: Data.t() | nil,
input: Data.t() | nil,
output: Data.t() | nil,
to_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
to_address_hash: Hash.Address.t() | nil,
trace_address: [non_neg_integer()],
transaction: %Ecto.Association.NotLoaded{} | Transaction.t(),
transaction_hash: Hash.t(),
transaction_index: Transaction.transaction_index() | nil,
value: Wei.t(),
block_hash: Hash.Full.t(),
block_index: non_neg_integer()
}
@primary_key false
schema "internal_transactions" do
typed_schema "internal_transactions" do
field(:call_type, CallType)
field(:created_contract_code, Data)
field(:error, :string)
field(:gas, :decimal)
field(:gas_used, :decimal)
field(:index, :integer, primary_key: true)
field(:index, :integer, primary_key: true, null: false)
field(:init, Data)
field(:input, Data)
field(:output, Data)
field(:trace_address, {:array, :integer})
field(:type, Type)
field(:value, Wei)
field(:trace_address, {:array, :integer}, null: false)
field(:type, Type, null: false)
field(:value, Wei, null: false)
field(:block_number, :integer)
field(:transaction_index, :integer)
field(:block_index, :integer)
field(:block_index, :integer, null: false)
timestamps()
@ -92,7 +65,8 @@ defmodule Explorer.Chain.InternalTransaction do
Address,
foreign_key: :from_address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
belongs_to(
@ -107,13 +81,15 @@ defmodule Explorer.Chain.InternalTransaction do
foreign_key: :transaction_hash,
primary_key: true,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
belongs_to(:block, Block,
foreign_key: :block_hash,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
belongs_to(:pending_block, PendingBlockOperation,

@ -28,47 +28,34 @@ defmodule Explorer.Chain.Log do
* `transaction_hash` - foreign key for `transaction`.
* `index` - index of the log entry in all logs for the `transaction`
"""
@type t :: %__MODULE__{
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t(),
block_hash: Hash.Full.t(),
block_number: non_neg_integer() | nil,
data: Data.t(),
first_topic: Hash.Full.t(),
second_topic: Hash.Full.t(),
third_topic: Hash.Full.t(),
fourth_topic: Hash.Full.t(),
transaction: %Ecto.Association.NotLoaded{} | Transaction.t(),
transaction_hash: Hash.Full.t(),
index: non_neg_integer()
}
@primary_key false
schema "logs" do
field(:data, Data)
typed_schema "logs" do
field(:data, Data, null: false)
field(:first_topic, Hash.Full)
field(:second_topic, Hash.Full)
field(:third_topic, Hash.Full)
field(:fourth_topic, Hash.Full)
field(:index, :integer, primary_key: true)
field(:index, :integer, primary_key: true, null: false)
field(:block_number, :integer)
timestamps()
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address, null: false)
belongs_to(:transaction, Transaction,
foreign_key: :transaction_hash,
primary_key: true,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
belongs_to(:block, Block,
foreign_key: :block_hash,
primary_key: true,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
end

@ -12,17 +12,19 @@ defmodule Explorer.Chain.PendingBlockOperation do
@typedoc """
* `block_hash` - the hash of the block that has pending operations.
"""
@type t :: %__MODULE__{
block_hash: Hash.Full.t()
}
@primary_key false
schema "pending_block_operations" do
typed_schema "pending_block_operations" do
timestamps()
field(:block_number, :integer)
field(:block_number, :integer, null: false)
belongs_to(:block, Block, foreign_key: :block_hash, primary_key: true, references: :hash, type: Hash.Full)
belongs_to(:block, Block,
foreign_key: :block_hash,
primary_key: true,
references: :hash,
type: Hash.Full,
null: false
)
end
def changeset(%__MODULE__{} = pending_ops, attrs) do

@ -22,23 +22,14 @@ defmodule Explorer.Chain.PolygonEdge.Deposit do
* `l1_timestamp` - timestamp of the L1 transaction block
* `l1_block_number` - block number of the L1 transaction
"""
@type t :: %__MODULE__{
msg_id: non_neg_integer(),
from: Hash.Address.t() | nil,
to: Hash.Address.t() | nil,
l1_transaction_hash: Hash.t() | nil,
l1_timestamp: DateTime.t() | nil,
l1_block_number: Block.block_number()
}
@primary_key false
schema "polygon_edge_deposits" do
field(:msg_id, :integer, primary_key: true)
typed_schema "polygon_edge_deposits" do
field(:msg_id, :integer, primary_key: true, null: false)
field(:from, Hash.Address)
field(:to, Hash.Address)
field(:l1_transaction_hash, Hash.Full)
field(:l1_timestamp, :utc_datetime_usec)
field(:l1_block_number, :integer)
field(:l1_block_number, :integer) :: Block.block_number()
timestamps()
end

@ -3,7 +3,7 @@ defmodule Explorer.Chain.PolygonEdge.DepositExecute do
use Explorer.Schema
alias Explorer.Chain.{Block, Hash}
alias Explorer.Chain.Hash
@required_attrs ~w(msg_id l2_transaction_hash l2_block_number success)a
@ -13,19 +13,12 @@ defmodule Explorer.Chain.PolygonEdge.DepositExecute do
* `l2_block_number` - block number of the L2 transaction
* `success` - a status of onStateReceive internal call (namely internal deposit transaction)
"""
@type t :: %__MODULE__{
msg_id: non_neg_integer(),
l2_transaction_hash: Hash.t(),
l2_block_number: Block.block_number(),
success: boolean()
}
@primary_key false
schema "polygon_edge_deposit_executes" do
field(:msg_id, :integer, primary_key: true)
field(:l2_transaction_hash, Hash.Full)
field(:l2_block_number, :integer)
field(:success, :boolean)
typed_schema "polygon_edge_deposit_executes" do
field(:msg_id, :integer, primary_key: true, null: false)
field(:l2_transaction_hash, Hash.Full, null: false)
field(:l2_block_number, :integer, null: false)
field(:success, :boolean, null: false)
timestamps()
end

@ -23,26 +23,21 @@ defmodule Explorer.Chain.PolygonEdge.Withdrawal do
* `l2_transaction_hash` - hash of the L2 transaction containing the corresponding L2StateSynced event
* `l2_block_number` - block number of the L2 transaction
"""
@type t :: %__MODULE__{
msg_id: non_neg_integer(),
from: Hash.Address.t() | nil,
from_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
to: Hash.Address.t() | nil,
to_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
l2_transaction_hash: Hash.t(),
l2_transaction: %Ecto.Association.NotLoaded{} | Transaction.t(),
l2_block_number: Block.block_number(),
l2_block: %Ecto.Association.NotLoaded{} | Block.t()
}
@primary_key false
schema "polygon_edge_withdrawals" do
field(:msg_id, :integer, primary_key: true)
typed_schema "polygon_edge_withdrawals" do
field(:msg_id, :integer, primary_key: true, null: false)
belongs_to(:from_address, Address, foreign_key: :from, references: :hash, type: Hash.Address)
belongs_to(:to_address, Address, foreign_key: :to, references: :hash, type: Hash.Address)
belongs_to(:l2_transaction, Transaction, foreign_key: :l2_transaction_hash, references: :hash, type: Hash.Full)
belongs_to(:l2_block, Block, foreign_key: :l2_block_number, references: :number, type: :integer)
belongs_to(:l2_transaction, Transaction,
foreign_key: :l2_transaction_hash,
references: :hash,
type: Hash.Full,
null: false
)
belongs_to(:l2_block, Block, foreign_key: :l2_block_number, references: :number, type: :integer, null: false)
timestamps()
end

@ -13,19 +13,12 @@ defmodule Explorer.Chain.PolygonEdge.WithdrawalExit do
* `l1_block_number` - block number of the L1 transaction
* `success` - a status of onL2StateReceive internal call (namely internal withdrawal transaction)
"""
@type t :: %__MODULE__{
msg_id: non_neg_integer(),
l1_transaction_hash: Hash.t(),
l1_block_number: Block.block_number(),
success: boolean()
}
@primary_key false
schema "polygon_edge_withdrawal_exits" do
field(:msg_id, :integer, primary_key: true)
field(:l1_transaction_hash, Hash.Full)
field(:l1_block_number, :integer)
field(:success, :boolean)
typed_schema "polygon_edge_withdrawal_exits" do
field(:msg_id, :integer, primary_key: true, null: false)
field(:l1_transaction_hash, Hash.Full, null: false)
field(:l1_block_number, :integer) :: Block.block_number()
field(:success, :boolean, null: false)
timestamps()
end

@ -5,6 +5,7 @@ defmodule Explorer.Chain.Shibarium.Bridge do
alias Explorer.Chain.{
Address,
Block,
Hash,
Transaction
}
@ -31,35 +32,16 @@ defmodule Explorer.Chain.Shibarium.Bridge do
* `token_type` - `bone` or `eth` or `other`
* `timestamp` - timestamp of the operation block (L1 block for deposit, L2 block - for withdrawal)
"""
@type t :: %__MODULE__{
user_address: %Ecto.Association.NotLoaded{} | Address.t(),
user: Hash.Address.t(),
amount_or_id: Decimal.t() | nil,
erc1155_ids: [non_neg_integer()] | nil,
erc1155_amounts: [Decimal.t()] | nil,
l1_transaction_hash: Hash.t(),
l1_block_number: non_neg_integer() | nil,
l2_transaction: %Ecto.Association.NotLoaded{} | Transaction.t() | nil,
l2_transaction_hash: Hash.t(),
l2_block_number: non_neg_integer() | nil,
operation_hash: Hash.t(),
operation_type: String.t(),
token_type: String.t(),
timestamp: DateTime.t(),
inserted_at: DateTime.t(),
updated_at: DateTime.t()
}
@primary_key false
schema "shibarium_bridge" do
belongs_to(:user_address, Address, foreign_key: :user, references: :hash, type: Hash.Address)
typed_schema "shibarium_bridge" do
belongs_to(:user_address, Address, foreign_key: :user, references: :hash, type: Hash.Address, null: false)
field(:amount_or_id, :decimal)
field(:erc1155_ids, {:array, :decimal})
field(:erc1155_amounts, {:array, :decimal})
field(:operation_hash, Hash.Full, primary_key: true)
field(:operation_type, Ecto.Enum, values: [:deposit, :withdrawal])
field(:operation_hash, Hash.Full, primary_key: true, null: false)
field(:operation_type, Ecto.Enum, values: [:deposit, :withdrawal], null: false)
field(:l1_transaction_hash, Hash.Full, primary_key: true)
field(:l1_block_number, :integer)
field(:l1_block_number, :integer) :: Block.block_number() | nil
belongs_to(:l2_transaction, Transaction,
foreign_key: :l2_transaction_hash,
@ -68,8 +50,8 @@ defmodule Explorer.Chain.Shibarium.Bridge do
primary_key: true
)
field(:l2_block_number, :integer)
field(:token_type, Ecto.Enum, values: [:bone, :eth, :other])
field(:l2_block_number, :integer) :: Block.block_number() | nil
field(:token_type, Ecto.Enum, values: [:bone, :eth, :other], null: false)
field(:timestamp, :utc_datetime_usec)
timestamps()

@ -246,37 +246,11 @@ defmodule Explorer.Chain.SmartContract do
* `is_yul` - field was added for storing user's choice
* `verified_via_eth_bytecode_db` - whether contract automatically verified via eth-bytecode-db or not.
"""
@type t :: %SmartContract{
name: String.t(),
compiler_version: String.t(),
optimization: boolean,
contract_source_code: String.t(),
constructor_arguments: String.t() | nil,
evm_version: String.t() | nil,
optimization_runs: non_neg_integer() | nil,
abi: [function_description],
verified_via_sourcify: boolean | nil,
partially_verified: boolean | nil,
file_path: String.t(),
is_vyper_contract: boolean | nil,
is_changed_bytecode: boolean,
bytecode_checked_at: DateTime.t(),
contract_code_md5: String.t(),
implementation_name: String.t() | nil,
compiler_settings: map() | nil,
implementation_fetched_at: DateTime.t(),
implementation_address_hash: Hash.Address.t(),
autodetect_constructor_args: boolean | nil,
is_yul: boolean | nil,
verified_via_eth_bytecode_db: boolean | nil
}
schema "smart_contracts" do
field(:name, :string)
field(:compiler_version, :string)
field(:optimization, :boolean)
field(:contract_source_code, :string)
typed_schema "smart_contracts" do
field(:name, :string, null: false)
field(:compiler_version, :string, null: false)
field(:optimization, :boolean, null: false)
field(:contract_source_code, :string, null: false)
field(:constructor_arguments, :string)
field(:evm_version, :string)
field(:optimization_runs, :integer)
@ -288,7 +262,7 @@ defmodule Explorer.Chain.SmartContract do
field(:is_vyper_contract, :boolean)
field(:is_changed_bytecode, :boolean, default: false)
field(:bytecode_checked_at, :utc_datetime_usec, default: DateTime.add(DateTime.utc_now(), -86400, :second))
field(:contract_code_md5, :string)
field(:contract_code_md5, :string, null: false)
field(:implementation_name, :string)
field(:compiler_settings, :map)
field(:implementation_fetched_at, :utc_datetime_usec, default: nil)
@ -309,7 +283,8 @@ defmodule Explorer.Chain.SmartContract do
Address,
foreign_key: :address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
has_many(:smart_contract_additional_sources, SmartContractAdditionalSource,

@ -11,32 +11,17 @@ defmodule Explorer.Chain.SmartContract.AuditReport do
@max_reports_per_day_for_contract 5
@type t :: %__MODULE__{
address_hash: Hash.Address.t(),
is_approved: boolean(),
submitter_name: String.t(),
submitter_email: String.t(),
is_project_owner: boolean(),
project_name: String.t(),
project_url: String.t(),
audit_company_name: String.t(),
audit_report_url: String.t(),
audit_publish_date: Date.t(),
request_id: String.t(),
comment: String.t()
}
schema "smart_contract_audit_reports" do
field(:address_hash, Hash.Address)
typed_schema "smart_contract_audit_reports" do
field(:address_hash, Hash.Address, null: false)
field(:is_approved, :boolean)
field(:submitter_name, :string)
field(:submitter_email, :string)
field(:is_project_owner, :boolean)
field(:project_name, :string)
field(:project_url, :string)
field(:audit_company_name, :string)
field(:audit_report_url, :string)
field(:audit_publish_date, :date)
field(:submitter_name, :string, null: false)
field(:submitter_email, :string, null: false)
field(:is_project_owner, :boolean, null: false)
field(:project_name, :string, null: false)
field(:project_url, :string, null: false)
field(:audit_company_name, :string, null: false)
field(:audit_report_url, :string, null: false)
field(:audit_publish_date, :date, null: false)
field(:request_id, :string)
field(:comment, :string)

@ -3,9 +3,9 @@ defmodule Explorer.Chain.SmartContract.ExternalLibrary do
The representation of an external library that was used for a smart contract.
"""
use Ecto.Schema
use Explorer.Schema
embedded_schema do
typed_embedded_schema do
field(:name)
field(:address_hash)
end

@ -10,25 +10,18 @@ defmodule Explorer.Chain.SmartContract.Proxy.VerificationStatus do
alias Explorer.Chain.Hash
alias Explorer.{Chain, Repo}
@typep status :: integer() | atom()
@typedoc """
* `contract_address_hash` - address of the contract which was tried to verify
* `status` - submission status: :pending | :pass | :fail
* `uid` - unique verification identifier
"""
@type t :: %__MODULE__{
uid: String.t(),
contract_address_hash: Hash.Address.t(),
status: non_neg_integer() | atom()
}
@typep status :: integer() | atom()
@primary_key false
schema "proxy_smart_contract_verification_statuses" do
field(:uid, :string, primary_key: true)
field(:status, Ecto.Enum, values: [pending: 0, pass: 1, fail: 2])
field(:contract_address_hash, Hash.Address)
typed_schema "proxy_smart_contract_verification_statuses" do
field(:uid, :string, primary_key: true, null: false)
field(:status, Ecto.Enum, values: [pending: 0, pass: 1, fail: 2], null: false)
field(:contract_address_hash, Hash.Address, null: false)
timestamps()
end

@ -12,21 +12,14 @@ defmodule Explorer.Chain.SmartContract.VerificationStatus do
@typedoc """
* `address_hash` - address of the contract which was tried to verify
* `status` - try status: :pending | :pass | :fail
* `status` - try status: :pending | :pass | :fail
* `uid` - unique verification try identifier
"""
@type t :: %__MODULE__{
uid: String.t(),
address_hash: Hash.Address.t(),
status: non_neg_integer()
}
@primary_key false
schema "contract_verification_status" do
field(:uid, :string, primary_key: true)
field(:status, :integer)
field(:address_hash, Hash.Address)
typed_schema "contract_verification_status" do
field(:uid, :string, primary_key: true, null: false)
field(:status, :integer, null: false)
field(:address_hash, Hash.Address, null: false)
timestamps()
end

@ -17,23 +17,17 @@ defmodule Explorer.Chain.SmartContractAdditionalSource do
* `contract_source_code` - the Solidity source code from the file with `file_name`.
* `address_hash` - foreign key for `smart_contract`.
"""
@type t :: %Explorer.Chain.SmartContractAdditionalSource{
file_name: String.t(),
contract_source_code: String.t(),
address_hash: Hash.Address.t()
}
schema "smart_contracts_additional_sources" do
field(:file_name, :string)
field(:contract_source_code, :string)
typed_schema "smart_contracts_additional_sources" do
field(:file_name, :string, null: false)
field(:contract_source_code, :string, null: false)
belongs_to(
:smart_contract,
SmartContract,
foreign_key: :address_hash,
references: :address_hash,
type: Hash.Address
type: Hash.Address,
null: false
)
timestamps()

@ -1,3 +1,54 @@
defmodule Explorer.Chain.Token.Schema do
@moduledoc false
alias Explorer.Chain.{Address, Hash}
if Application.compile_env(:explorer, Explorer.Chain.BridgedToken)[:enabled] do
@bridged_field [
quote do
field(:bridged, :boolean)
end
]
else
@bridged_field []
end
defmacro generate do
quote do
@primary_key false
typed_schema "tokens" do
field(:name, :string)
field(:symbol, :string)
field(:total_supply, :decimal)
field(:decimals, :decimal)
field(:type, :string, null: false)
field(:cataloged, :boolean)
field(:holder_count, :integer)
field(:skip_metadata, :boolean)
field(:total_supply_updated_at_block, :integer)
field(:fiat_value, :decimal)
field(:circulating_market_cap, :decimal)
field(:icon_url, :string)
field(:is_verified_via_admin_panel, :boolean)
belongs_to(
:contract_address,
Address,
foreign_key: :contract_address_hash,
primary_key: true,
references: :hash,
type: Hash.Address,
null: false
)
unquote_splicing(@bridged_field)
timestamps()
end
end
end
end
defmodule Explorer.Chain.Token do
@moduledoc """
Represents a token.
@ -20,11 +71,13 @@ defmodule Explorer.Chain.Token do
use Explorer.Schema
require Explorer.Chain.Token.Schema
import Ecto.{Changeset, Query}
alias Ecto.Changeset
alias Explorer.{Chain, SortingHelper}
alias Explorer.Chain.{Address, BridgedToken, Hash, Search, Token}
alias Explorer.Chain.{BridgedToken, Search, Token}
alias Explorer.SmartContract.Helper
@default_sorting [
@ -35,15 +88,21 @@ defmodule Explorer.Chain.Token do
asc: :contract_address_hash
]
if Application.compile_env(:explorer, Explorer.Chain.BridgedToken)[:enabled] do
@bridged_field quote(
do: [
bridged: boolean()
]
)
else
@bridged_field quote(do: [])
end
@derive {Poison.Encoder,
except: [
:__meta__,
:contract_address,
:inserted_at,
:updated_at
]}
@derive {Jason.Encoder,
except: [
:__meta__,
:contract_address,
:inserted_at,
:updated_at
]}
@typedoc """
* `name` - Name of the token
@ -61,73 +120,7 @@ defmodule Explorer.Chain.Token do
* `icon_url` - URL of the token's icon.
* `is_verified_via_admin_panel` - is token verified via admin panel.
"""
@type t ::
%Token{
unquote_splicing(@bridged_field),
name: String.t(),
symbol: String.t(),
total_supply: Decimal.t() | nil,
decimals: non_neg_integer(),
type: String.t(),
cataloged: boolean(),
contract_address: %Ecto.Association.NotLoaded{} | Address.t(),
contract_address_hash: Hash.Address.t(),
holder_count: non_neg_integer() | nil,
skip_metadata: boolean(),
total_supply_updated_at_block: non_neg_integer() | nil,
fiat_value: Decimal.t() | nil,
circulating_market_cap: Decimal.t() | nil,
icon_url: String.t(),
is_verified_via_admin_panel: boolean()
}
@derive {Poison.Encoder,
except: [
:__meta__,
:contract_address,
:inserted_at,
:updated_at
]}
@derive {Jason.Encoder,
except: [
:__meta__,
:contract_address,
:inserted_at,
:updated_at
]}
@primary_key false
schema "tokens" do
field(:name, :string)
field(:symbol, :string)
field(:total_supply, :decimal)
field(:decimals, :decimal)
field(:type, :string)
field(:cataloged, :boolean)
field(:holder_count, :integer)
field(:skip_metadata, :boolean)
field(:total_supply_updated_at_block, :integer)
field(:fiat_value, :decimal)
field(:circulating_market_cap, :decimal)
field(:icon_url, :string)
field(:is_verified_via_admin_panel, :boolean)
belongs_to(
:contract_address,
Address,
foreign_key: :contract_address_hash,
primary_key: true,
references: :hash,
type: Hash.Address
)
if Application.compile_env(:explorer, BridgedToken)[:enabled] do
field(:bridged, :boolean)
end
timestamps()
end
Explorer.Chain.Token.Schema.generate()
@required_attrs ~w(contract_address_hash type)a
@optional_attrs ~w(cataloged decimals name symbol total_supply skip_metadata total_supply_updated_at_block updated_at fiat_value circulating_market_cap icon_url is_verified_via_admin_panel)a

@ -6,7 +6,7 @@ defmodule Explorer.Chain.Token.Instance do
use Explorer.Schema
alias Explorer.{Chain, Helper}
alias Explorer.Chain.{Address, Block, Hash, Token, TokenTransfer}
alias Explorer.Chain.{Address, Hash, Token, TokenTransfer}
alias Explorer.Chain.Address.CurrentTokenBalance
alias Explorer.Chain.Token.Instance
alias Explorer.PagingOptions
@ -17,22 +17,9 @@ defmodule Explorer.Chain.Token.Instance do
* `metadata` - Token instance metadata
* `error` - error fetching token instance
"""
@type t :: %Instance{
token_id: non_neg_integer(),
token_contract_address_hash: Hash.Address.t() | nil,
metadata: map() | nil,
error: String.t() | nil,
owner_address_hash: Hash.Address.t() | nil,
owner_updated_at_block: Block.block_number() | nil,
owner_updated_at_log_index: non_neg_integer() | nil,
current_token_balance: any(),
is_unique: bool() | nil
}
@primary_key false
schema "token_instances" do
field(:token_id, :decimal, primary_key: true)
typed_schema "token_instances" do
field(:token_id, :decimal, primary_key: true, null: false)
field(:metadata, :map)
field(:error, :string)
field(:owner_updated_at_block, :integer)
@ -48,7 +35,8 @@ defmodule Explorer.Chain.Token.Instance do
foreign_key: :token_contract_address_hash,
references: :contract_address_hash,
type: Hash.Address,
primary_key: true
primary_key: true,
null: false
)
timestamps()
@ -106,7 +94,7 @@ defmodule Explorer.Chain.Token.Instance do
|> select([ctb], ctb.address_hash)
end
@spec token_instance_query(non_neg_integer(), Hash.Address.t()) :: Ecto.Query.t()
@spec token_instance_query(Decimal.t() | non_neg_integer(), Hash.Address.t()) :: Ecto.Query.t()
def token_instance_query(token_id, token_contract_address),
do: from(i in Instance, where: i.token_contract_address_hash == ^token_contract_address and i.token_id == ^token_id)

@ -33,6 +33,17 @@ defmodule Explorer.Chain.TokenTransfer do
@default_paging_options %PagingOptions{page_size: 50}
@typep paging_options :: {:paging_options, PagingOptions.t()}
@typep api? :: {:api?, true | false}
@constant "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
@weth_deposit_signature "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
@weth_withdrawal_signature "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"
@erc1155_single_transfer_signature "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"
@erc1155_batch_transfer_signature "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"
@transfer_function_signature "0xa9059cbb"
@typedoc """
* `:amount` - The token transferred amount
* `:block_hash` - hash of the block
@ -49,67 +60,47 @@ defmodule Explorer.Chain.TokenTransfer do
* `:amounts` - Tokens transferred amounts in case of batched transfer in ERC-1155
* `:token_ids` - IDs of the tokens (applicable to ERC-1155 tokens)
"""
@type t :: %TokenTransfer{
amount: Decimal.t() | nil,
block_number: non_neg_integer() | nil,
block_hash: Hash.Full.t(),
from_address: %Ecto.Association.NotLoaded{} | Address.t(),
from_address_hash: Hash.Address.t(),
to_address: %Ecto.Association.NotLoaded{} | Address.t(),
to_address_hash: Hash.Address.t(),
token_contract_address: %Ecto.Association.NotLoaded{} | Address.t(),
token_contract_address_hash: Hash.Address.t(),
transaction: %Ecto.Association.NotLoaded{} | Transaction.t(),
transaction_hash: Hash.Full.t(),
log_index: non_neg_integer(),
amounts: [Decimal.t()] | nil,
token_ids: [non_neg_integer()] | nil,
index_in_batch: non_neg_integer() | nil
}
@typep paging_options :: {:paging_options, PagingOptions.t()}
@typep api? :: {:api?, true | false}
@constant "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
@weth_deposit_signature "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c"
@weth_withdrawal_signature "0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65"
@erc1155_single_transfer_signature "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62"
@erc1155_batch_transfer_signature "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"
@transfer_function_signature "0xa9059cbb"
@primary_key false
schema "token_transfers" do
typed_schema "token_transfers" do
field(:amount, :decimal)
field(:block_number, :integer)
field(:log_index, :integer, primary_key: true)
field(:block_number, :integer) :: Block.block_number()
field(:log_index, :integer, primary_key: true, null: false)
field(:amounts, {:array, :decimal})
field(:token_ids, {:array, :decimal})
field(:index_in_batch, :integer, virtual: true)
belongs_to(:from_address, Address, foreign_key: :from_address_hash, references: :hash, type: Hash.Address)
belongs_to(:to_address, Address, foreign_key: :to_address_hash, references: :hash, type: Hash.Address)
belongs_to(:from_address, Address,
foreign_key: :from_address_hash,
references: :hash,
type: Hash.Address,
null: false
)
belongs_to(:to_address, Address, foreign_key: :to_address_hash, references: :hash, type: Hash.Address, null: false)
belongs_to(
:token_contract_address,
Address,
foreign_key: :token_contract_address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
belongs_to(:transaction, Transaction,
foreign_key: :transaction_hash,
primary_key: true,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
belongs_to(:block, Block,
foreign_key: :block_hash,
primary_key: true,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
has_many(

@ -1,40 +1,195 @@
defmodule Explorer.Chain.Transaction.Schema do
@moduledoc false
alias Explorer.Chain.{
Address,
Block,
Data,
Hash,
InternalTransaction,
Log,
TokenTransfer,
TransactionAction,
Wei
}
alias Explorer.Chain.Transaction.{Fork, Status}
alias Explorer.Chain.Zkevm.BatchTransaction
@chain_type_fields (case Application.compile_env(:explorer, :chain_type) do
"suave" ->
elem(
quote do
belongs_to(
:execution_node,
Address,
foreign_key: :execution_node_hash,
references: :hash,
type: Hash.Address
)
field(:wrapped_type, :integer)
field(:wrapped_nonce, :integer)
field(:wrapped_gas, :decimal)
field(:wrapped_gas_price, Wei)
field(:wrapped_max_priority_fee_per_gas, Wei)
field(:wrapped_max_fee_per_gas, Wei)
field(:wrapped_value, Wei)
field(:wrapped_input, Data)
field(:wrapped_v, :decimal)
field(:wrapped_r, :decimal)
field(:wrapped_s, :decimal)
field(:wrapped_hash, Hash.Full)
belongs_to(
:wrapped_to_address,
Address,
foreign_key: :wrapped_to_address_hash,
references: :hash,
type: Hash.Address
)
end,
2
)
"polygon_zkevm" ->
elem(
quote do
has_one(:zkevm_batch_transaction, BatchTransaction, foreign_key: :hash, references: :hash)
has_one(:zkevm_batch, through: [:zkevm_batch_transaction, :batch], references: :hash)
has_one(:zkevm_sequence_transaction,
through: [:zkevm_batch, :sequence_transaction],
references: :hash
)
has_one(:zkevm_verify_transaction,
through: [:zkevm_batch, :verify_transaction],
references: :hash
)
end,
2
)
_ ->
[]
end)
defmacro generate do
quote do
@primary_key false
typed_schema "transactions" do
field(:hash, Hash.Full, primary_key: true)
field(:block_number, :integer)
field(:block_consensus, :boolean)
field(:block_timestamp, :utc_datetime_usec)
field(:cumulative_gas_used, :decimal)
field(:earliest_processing_start, :utc_datetime_usec)
field(:error, :string)
field(:gas, :decimal)
field(:gas_price, Wei)
field(:gas_used, :decimal)
field(:index, :integer)
field(:created_contract_code_indexed_at, :utc_datetime_usec)
field(:input, Data)
field(:nonce, :integer) :: non_neg_integer() | nil
field(:r, :decimal)
field(:s, :decimal)
field(:status, Status)
field(:v, :decimal)
field(:value, Wei)
field(:revert_reason, :string)
field(:max_priority_fee_per_gas, Wei)
field(:max_fee_per_gas, Wei)
field(:type, :integer)
field(:has_error_in_internal_txs, :boolean)
field(:has_token_transfers, :boolean, virtual: true)
# stability virtual fields
field(:transaction_fee_log, :any, virtual: true)
field(:transaction_fee_token, :any, virtual: true)
# A transient field for deriving old block hash during transaction upserts.
# Used to force refetch of a block in case a transaction is re-collated
# in a different block. See: https://github.com/blockscout/blockscout/issues/1911
field(:old_block_hash, Hash.Full)
timestamps()
belongs_to(:block, Block, foreign_key: :block_hash, references: :hash, type: Hash.Full)
has_many(:forks, Fork, foreign_key: :hash, references: :hash)
belongs_to(
:from_address,
Address,
foreign_key: :from_address_hash,
references: :hash,
type: Hash.Address
)
has_many(:internal_transactions, InternalTransaction, foreign_key: :transaction_hash, references: :hash)
has_many(:logs, Log, foreign_key: :transaction_hash, references: :hash)
has_many(:token_transfers, TokenTransfer, foreign_key: :transaction_hash, references: :hash)
has_many(:transaction_actions, TransactionAction,
foreign_key: :hash,
preload_order: [asc: :log_index],
references: :hash
)
belongs_to(
:to_address,
Address,
foreign_key: :to_address_hash,
references: :hash,
type: Hash.Address
)
has_many(:uncles, through: [:forks, :uncle], references: :hash)
belongs_to(
:created_contract_address,
Address,
foreign_key: :created_contract_address_hash,
references: :hash,
type: Hash.Address
)
unquote_splicing(@chain_type_fields)
end
end
end
end
defmodule Explorer.Chain.Transaction do
@moduledoc "Models a Web3 transaction."
use Explorer.Schema
require Logger
require Explorer.Chain.Transaction.Schema
alias ABI.FunctionSelector
alias Ecto.Association.NotLoaded
alias Ecto.Changeset
alias Explorer.{Chain, Repo}
alias Explorer.{Chain, Helper, PagingOptions, Repo, SortingHelper}
alias Explorer.Chain.{
Address,
Block,
Block.Reward,
ContractMethod,
Data,
DenormalizationHelper,
Gas,
Hash,
InternalTransaction,
Log,
SmartContract,
SmartContract.Proxy,
Token,
TokenTransfer,
Transaction,
TransactionAction,
Wei
}
alias Explorer.Chain.Block.Reward
alias Explorer.Chain.SmartContract.Proxy
alias Explorer.Chain.Transaction.{Fork, Status}
alias Explorer.Chain.Zkevm.BatchTransaction
alias Explorer.{PagingOptions, SortingHelper}
alias Explorer.SmartContract.SigProviderInterface
@optional_attrs ~w(max_priority_fee_per_gas max_fee_per_gas block_hash block_number block_consensus block_timestamp created_contract_address_hash cumulative_gas_used earliest_processing_start
@ -85,6 +240,48 @@ defmodule Explorer.Chain.Transaction do
"""
@type wei_per_gas :: Wei.t()
@derive {Poison.Encoder,
only: [
:block_number,
:block_timestamp,
:cumulative_gas_used,
:error,
:gas,
:gas_price,
:gas_used,
:index,
:created_contract_code_indexed_at,
:input,
:nonce,
:r,
:s,
:v,
:status,
:value,
:revert_reason
]}
@derive {Jason.Encoder,
only: [
:block_number,
:block_timestamp,
:cumulative_gas_used,
:error,
:gas,
:gas_price,
:gas_used,
:index,
:created_contract_code_indexed_at,
:input,
:nonce,
:r,
:s,
:v,
:status,
:value,
:revert_reason
]}
@typedoc """
* `block` - the block in which this transaction was mined/validated. `nil` when transaction is pending or has only
been collated into one of the `uncles` in one of the `forks`.
@ -166,224 +363,7 @@ defmodule Explorer.Chain.Transaction do
* `wrapped_s` - S field of the signature from the `wrapped` field (used by Suave)
* `wrapped_hash` - hash from the `wrapped` field (used by Suave)
"""
@type t ::
Map.merge(
%__MODULE__{
block: %Ecto.Association.NotLoaded{} | Block.t() | nil,
block_hash: Hash.t() | nil,
block_number: Block.block_number() | nil,
block_consensus: boolean(),
block_timestamp: DateTime.t() | nil,
created_contract_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
created_contract_address_hash: Hash.Address.t() | nil,
created_contract_code_indexed_at: DateTime.t() | nil,
cumulative_gas_used: Gas.t() | nil,
earliest_processing_start: DateTime.t() | nil,
error: String.t() | nil,
forks: %Ecto.Association.NotLoaded{} | [Fork.t()],
from_address: %Ecto.Association.NotLoaded{} | Address.t(),
from_address_hash: Hash.Address.t(),
gas: Gas.t(),
gas_price: wei_per_gas | nil,
gas_used: Gas.t() | nil,
hash: Hash.t(),
index: transaction_index | nil,
input: Data.t(),
internal_transactions: %Ecto.Association.NotLoaded{} | [InternalTransaction.t()],
logs: %Ecto.Association.NotLoaded{} | [Log.t()],
nonce: non_neg_integer(),
r: r(),
s: s(),
status: Status.t() | nil,
to_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
to_address_hash: Hash.Address.t() | nil,
uncles: %Ecto.Association.NotLoaded{} | [Block.t()],
v: v(),
value: Wei.t(),
revert_reason: String.t() | nil,
max_priority_fee_per_gas: wei_per_gas | nil,
max_fee_per_gas: wei_per_gas | nil,
type: non_neg_integer() | nil,
has_error_in_internal_txs: boolean(),
transaction_fee_log: any(),
transaction_fee_token: any()
},
suave
)
if Application.compile_env(:explorer, :chain_type) == "suave" do
@type suave :: %{
execution_node: %Ecto.Association.NotLoaded{} | Address.t() | nil,
execution_node_hash: Hash.Address.t() | nil,
wrapped_type: non_neg_integer() | nil,
wrapped_nonce: non_neg_integer() | nil,
wrapped_to_address: %Ecto.Association.NotLoaded{} | Address.t() | nil,
wrapped_to_address_hash: Hash.Address.t() | nil,
wrapped_gas: Gas.t() | nil,
wrapped_gas_price: wei_per_gas | nil,
wrapped_max_priority_fee_per_gas: wei_per_gas | nil,
wrapped_max_fee_per_gas: wei_per_gas | nil,
wrapped_value: Wei.t() | nil,
wrapped_input: Data.t() | nil,
wrapped_v: v() | nil,
wrapped_r: r() | nil,
wrapped_s: s() | nil,
wrapped_hash: Hash.t() | nil
}
else
@type suave :: %{}
end
@derive {Poison.Encoder,
only: [
:block_number,
:block_timestamp,
:cumulative_gas_used,
:error,
:gas,
:gas_price,
:gas_used,
:index,
:created_contract_code_indexed_at,
:input,
:nonce,
:r,
:s,
:v,
:status,
:value,
:revert_reason
]}
@derive {Jason.Encoder,
only: [
:block_number,
:block_timestamp,
:cumulative_gas_used,
:error,
:gas,
:gas_price,
:gas_used,
:index,
:created_contract_code_indexed_at,
:input,
:nonce,
:r,
:s,
:v,
:status,
:value,
:revert_reason
]}
@primary_key {:hash, Hash.Full, autogenerate: false}
schema "transactions" do
field(:block_number, :integer)
field(:block_consensus, :boolean)
field(:block_timestamp, :utc_datetime_usec)
field(:cumulative_gas_used, :decimal)
field(:earliest_processing_start, :utc_datetime_usec)
field(:error, :string)
field(:gas, :decimal)
field(:gas_price, Wei)
field(:gas_used, :decimal)
field(:index, :integer)
field(:created_contract_code_indexed_at, :utc_datetime_usec)
field(:input, Data)
field(:nonce, :integer)
field(:r, :decimal)
field(:s, :decimal)
field(:status, Status)
field(:v, :decimal)
field(:value, Wei)
field(:revert_reason, :string)
field(:max_priority_fee_per_gas, Wei)
field(:max_fee_per_gas, Wei)
field(:type, :integer)
field(:has_error_in_internal_txs, :boolean)
field(:has_token_transfers, :boolean, virtual: true)
# stability virtual fields
field(:transaction_fee_log, :any, virtual: true)
field(:transaction_fee_token, :any, virtual: true)
# A transient field for deriving old block hash during transaction upserts.
# Used to force refetch of a block in case a transaction is re-collated
# in a different block. See: https://github.com/blockscout/blockscout/issues/1911
field(:old_block_hash, Hash.Full)
timestamps()
belongs_to(:block, Block, foreign_key: :block_hash, references: :hash, type: Hash.Full)
has_many(:forks, Fork, foreign_key: :hash)
belongs_to(
:from_address,
Address,
foreign_key: :from_address_hash,
references: :hash,
type: Hash.Address
)
has_many(:internal_transactions, InternalTransaction, foreign_key: :transaction_hash)
has_many(:logs, Log, foreign_key: :transaction_hash)
has_many(:token_transfers, TokenTransfer, foreign_key: :transaction_hash)
has_many(:transaction_actions, TransactionAction, foreign_key: :hash, preload_order: [asc: :log_index])
belongs_to(
:to_address,
Address,
foreign_key: :to_address_hash,
references: :hash,
type: Hash.Address
)
has_many(:uncles, through: [:forks, :uncle])
has_one(:zkevm_batch_transaction, BatchTransaction, foreign_key: :hash)
has_one(:zkevm_batch, through: [:zkevm_batch_transaction, :batch])
has_one(:zkevm_sequence_transaction, through: [:zkevm_batch, :sequence_transaction])
has_one(:zkevm_verify_transaction, through: [:zkevm_batch, :verify_transaction])
belongs_to(
:created_contract_address,
Address,
foreign_key: :created_contract_address_hash,
references: :hash,
type: Hash.Address
)
if System.get_env("CHAIN_TYPE") == "suave" do
belongs_to(
:execution_node,
Address,
foreign_key: :execution_node_hash,
references: :hash,
type: Hash.Address
)
field(:wrapped_type, :integer)
field(:wrapped_nonce, :integer)
field(:wrapped_gas, :decimal)
field(:wrapped_gas_price, Wei)
field(:wrapped_max_priority_fee_per_gas, Wei)
field(:wrapped_max_fee_per_gas, Wei)
field(:wrapped_value, Wei)
field(:wrapped_input, Data)
field(:wrapped_v, :decimal)
field(:wrapped_r, :decimal)
field(:wrapped_s, :decimal)
field(:wrapped_hash, Hash.Full)
belongs_to(
:wrapped_to_address,
Address,
foreign_key: :wrapped_to_address_hash,
references: :hash,
type: Hash.Address
)
end
end
Explorer.Chain.Transaction.Schema.generate()
@doc """
A pending transaction does not have a `block_hash`
@ -639,7 +619,7 @@ defmodule Explorer.Chain.Transaction do
def decoded_input_data(
%__MODULE__{
to_address: %NotLoaded{},
to_address: %{smart_contract: nil},
input: input,
hash: hash
},
@ -650,7 +630,7 @@ defmodule Explorer.Chain.Transaction do
) do
decoded_input_data(
%__MODULE__{
to_address: %{smart_contract: nil},
to_address: %NotLoaded{},
input: input,
hash: hash
},
@ -674,7 +654,7 @@ defmodule Explorer.Chain.Transaction do
) do
decoded_input_data(
%__MODULE__{
to_address: %{smart_contract: nil},
to_address: %NotLoaded{},
input: input,
hash: hash
},
@ -687,7 +667,7 @@ defmodule Explorer.Chain.Transaction do
def decoded_input_data(
%__MODULE__{
to_address: %{smart_contract: nil},
to_address: %NotLoaded{},
input: %{bytes: <<method_id::binary-size(4), _::binary>> = data} = input,
hash: hash
},
@ -714,7 +694,7 @@ defmodule Explorer.Chain.Transaction do
full_abi_acc, methods_acc}
end
def decoded_input_data(%__MODULE__{to_address: %{smart_contract: nil}}, _, _, full_abi_acc, methods_acc) do
def decoded_input_data(%__MODULE__{to_address: %NotLoaded{}}, _, _, full_abi_acc, methods_acc) do
{{:error, :contract_not_verified, []}, full_abi_acc, methods_acc}
end
@ -734,7 +714,7 @@ defmodule Explorer.Chain.Transaction do
{{:error, :could_not_decode}, full_abi_acc} ->
case decoded_input_data(
%__MODULE__{
to_address: %{smart_contract: nil},
to_address: %NotLoaded{},
input: input,
hash: hash
},
@ -830,7 +810,7 @@ defmodule Explorer.Chain.Transaction do
else
case decoded_input_data(
%__MODULE__{
to_address: %{smart_contract: nil},
to_address: %NotLoaded{},
input: transaction.input,
hash: transaction.hash
},
@ -1653,7 +1633,7 @@ defmodule Explorer.Chain.Transaction do
@doc """
Return the dynamic that calculates the fee for transactions.
"""
@spec dynamic_fee :: struct()
@spec dynamic_fee :: Ecto.Query.dynamic_expr()
def dynamic_fee do
dynamic([tx], tx.gas_price * fragment("COALESCE(?, ?)", tx.gas_used, tx.gas))
end
@ -1676,4 +1656,48 @@ defmodule Explorer.Chain.Transaction do
"hash" => hash
}
end
@suave_bid_event "0x83481d5b04dea534715acad673a8177a46fc93882760f36bdc16ccac439d504e"
@spec suave_parse_allowed_peekers(Ecto.Schema.has_many(Log.t())) :: [String.t()]
def suave_parse_allowed_peekers(%NotLoaded{}), do: []
def suave_parse_allowed_peekers(logs) do
suave_bid_contracts =
Application.get_all_env(:explorer)[Transaction][:suave_bid_contracts]
|> String.split(",")
|> Enum.map(fn sbc -> String.downcase(String.trim(sbc)) end)
bid_event =
Enum.find(logs, fn log ->
sanitize_log_first_topic(log.first_topic) == @suave_bid_event &&
Enum.member?(suave_bid_contracts, String.downcase(Hash.to_string(log.address_hash)))
end)
if is_nil(bid_event) do
[]
else
[_bid_id, _decryption_condition, allowed_peekers] =
Helper.decode_data(bid_event.data, [{:bytes, 16}, {:uint, 64}, {:array, :address}])
Enum.map(allowed_peekers, fn peeker ->
"0x" <> Base.encode16(peeker, case: :lower)
end)
end
end
defp sanitize_log_first_topic(first_topic) do
if is_nil(first_topic) do
""
else
sanitized =
if is_binary(first_topic) do
first_topic
else
Hash.to_string(first_topic)
end
String.downcase(sanitized)
end
end
end

@ -20,22 +20,14 @@ defmodule Explorer.Chain.Transaction.Fork do
* `uncle` - the block in which this transaction was mined/validated.
* `uncle_hash` - `uncle` foreign key.
"""
@type t :: %__MODULE__{
hash: Hash.t(),
index: Transaction.transaction_index(),
transaction: %Ecto.Association.NotLoaded{} | Transaction.t(),
uncle: %Ecto.Association.NotLoaded{} | Block.t(),
uncle_hash: Hash.t()
}
@primary_key false
schema "transaction_forks" do
field(:index, :integer)
typed_schema "transaction_forks" do
field(:index, :integer, null: false)
timestamps()
belongs_to(:transaction, Transaction, foreign_key: :hash, references: :hash, type: Hash.Full)
belongs_to(:uncle, Block, foreign_key: :uncle_hash, references: :hash, type: Hash.Full)
belongs_to(:transaction, Transaction, foreign_key: :hash, references: :hash, type: Hash.Full, null: false)
belongs_to(:uncle, Block, foreign_key: :uncle_hash, references: :hash, type: Hash.Full, null: false)
end
@doc """

@ -14,13 +14,6 @@ defmodule Explorer.Chain.Transaction.History.TransactionStats do
:__meta__
]}
schema "transaction_stats" do
field(:date, :date)
field(:number_of_transactions, :integer)
field(:gas_used, :decimal)
field(:total_fee, :decimal)
end
@typedoc """
The recorded values of the number of transactions for a single day.
* `:date` - The date in UTC.
@ -28,12 +21,12 @@ defmodule Explorer.Chain.Transaction.History.TransactionStats do
* `:gas_used` - Gas used in transactions per single day
* `:total_fee` - Total fee paid to validators from success transactions per single day
"""
@type t :: %__MODULE__{
date: Date.t(),
number_of_transactions: integer(),
gas_used: non_neg_integer(),
total_fee: non_neg_integer()
}
typed_schema "transaction_stats" do
field(:date, :date)
field(:number_of_transactions, :integer)
field(:gas_used, :decimal)
field(:total_fee, :decimal)
end
@spec by_date_range(Date.t(), Date.t()) :: [__MODULE__]
def by_date_range(earliest, latest, options \\ []) do

@ -18,18 +18,10 @@ defmodule Explorer.Chain.TransactionAction do
* `type` - type of the action protocol (see possible values for Enum of the db table field)
* `log_index` - index of the action for sorting (taken from log.index)
"""
@type t :: %__MODULE__{
hash: Hash.t(),
protocol: String.t(),
data: map(),
type: String.t(),
log_index: non_neg_integer()
}
@primary_key false
schema "transaction_actions" do
field(:protocol, Ecto.Enum, values: @supported_protocols)
field(:data, :map)
typed_schema "transaction_actions" do
field(:protocol, Ecto.Enum, values: @supported_protocols, null: false)
field(:data, :map, null: false)
field(:type, Ecto.Enum,
values: [
@ -54,12 +46,19 @@ defmodule Explorer.Chain.TransactionAction do
:enable_collateral,
:disable_collateral,
:liquidation_call
]
],
null: false
)
field(:log_index, :integer, primary_key: true)
field(:log_index, :integer, primary_key: true, null: false)
belongs_to(:transaction, Transaction, foreign_key: :hash, primary_key: true, references: :hash, type: Hash.Full)
belongs_to(:transaction, Transaction,
foreign_key: :hash,
primary_key: true,
references: :hash,
type: Hash.Full,
null: false
)
timestamps()
end

@ -22,18 +22,11 @@ defmodule Explorer.Chain.UserOperation do
* `block_number` - the block number, where user operation happened.
* `block_hash` - the block hash, where user operation happened.
"""
@type t :: %Explorer.Chain.UserOperation{
hash: Hash.Full.t(),
block_number: Explorer.Chain.Block.block_number() | nil,
block_hash: Hash.Full.t()
}
@primary_key false
schema "user_operations" do
field(:hash, Hash.Full, primary_key: true)
field(:block_number, :integer)
field(:block_hash, Hash.Full)
typed_schema "user_operations" do
field(:hash, Hash.Full, primary_key: true, null: false)
field(:block_number, :integer, null: false)
field(:block_hash, Hash.Full, null: false)
timestamps()
end

@ -8,8 +8,8 @@ defmodule Explorer.Chain.Validator do
alias Explorer.{Chain, Repo}
@primary_key false
schema "validators" do
field(:address_hash, Address, primary_key: true)
typed_schema "validators" do
field(:address_hash, Address, primary_key: true, null: false)
field(:is_validator, :boolean)
field(:payout_key_hash, Address)
field(:info_updated_at_block, :integer)

@ -8,33 +8,26 @@ defmodule Explorer.Chain.Withdrawal do
alias Explorer.Chain.{Address, Block, Hash, Wei}
alias Explorer.PagingOptions
@type t :: %__MODULE__{
index: non_neg_integer(),
validator_index: non_neg_integer(),
amount: Wei.t(),
block: %Ecto.Association.NotLoaded{} | Block.t(),
block_hash: Hash.Full.t(),
address: %Ecto.Association.NotLoaded{} | Address.t(),
address_hash: Hash.Address.t()
}
@required_attrs ~w(index validator_index amount address_hash block_hash)a
@primary_key {:index, :integer, autogenerate: false}
schema "withdrawals" do
field(:validator_index, :integer)
field(:amount, Wei)
@primary_key false
typed_schema "withdrawals" do
field(:index, :integer, primary_key: true, null: false)
field(:validator_index, :integer, null: false)
field(:amount, Wei, null: false)
belongs_to(:address, Address,
foreign_key: :address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
belongs_to(:block, Block,
foreign_key: :block_hash,
references: :hash,
type: Hash.Full
type: Hash.Full,
null: false
)
timestamps()

@ -8,19 +8,19 @@ defmodule Explorer.Chain.Zkevm.BatchTransaction do
@required_attrs ~w(batch_number hash)a
@type t :: %__MODULE__{
batch_number: non_neg_integer(),
batch: %Ecto.Association.NotLoaded{} | TransactionBatch.t() | nil,
hash: Hash.t(),
l2_transaction: %Ecto.Association.NotLoaded{} | Transaction.t() | nil
}
@primary_key false
schema "zkevm_batch_l2_transactions" do
belongs_to(:batch, TransactionBatch, foreign_key: :batch_number, references: :number, type: :integer)
belongs_to(:l2_transaction, Transaction, foreign_key: :hash, primary_key: true, references: :hash, type: Hash.Full)
typed_schema "zkevm_batch_l2_transactions" do
belongs_to(:batch, TransactionBatch, foreign_key: :batch_number, references: :number, type: :integer, null: false)
belongs_to(:l2_transaction, Transaction,
foreign_key: :hash,
primary_key: true,
references: :hash,
type: Hash.Full,
null: false
)
timestamps()
timestamps(null: false)
end
@doc """

@ -8,18 +8,14 @@ defmodule Explorer.Chain.Zkevm.LifecycleTransaction do
@required_attrs ~w(id hash is_verify)a
@type t :: %__MODULE__{
hash: Hash.t(),
is_verify: boolean()
}
@primary_key {:id, :integer, autogenerate: false}
schema "zkevm_lifecycle_l1_transactions" do
field(:hash, Hash.Full)
field(:is_verify, :boolean)
has_many(:sequenced_batches, TransactionBatch, foreign_key: :sequence_id)
has_many(:verified_batches, TransactionBatch, foreign_key: :verify_id)
@primary_key false
typed_schema "zkevm_lifecycle_l1_transactions" do
field(:id, :integer, primary_key: true, null: false)
field(:hash, Hash.Full, null: false)
field(:is_verify, :boolean, null: false)
has_many(:sequenced_batches, TransactionBatch, foreign_key: :sequence_id, references: :id)
has_many(:verified_batches, TransactionBatch, foreign_key: :verify_id, references: :id)
timestamps()
end

@ -10,22 +10,9 @@ defmodule Explorer.Chain.Zkevm.TransactionBatch do
@required_attrs ~w(number timestamp l2_transactions_count global_exit_root acc_input_hash state_root)a
@type t :: %__MODULE__{
number: non_neg_integer(),
timestamp: DateTime.t(),
l2_transactions_count: non_neg_integer(),
global_exit_root: Hash.t(),
acc_input_hash: Hash.t(),
state_root: Hash.t(),
sequence_id: non_neg_integer() | nil,
sequence_transaction: %Ecto.Association.NotLoaded{} | LifecycleTransaction.t() | nil,
verify_id: non_neg_integer() | nil,
verify_transaction: %Ecto.Association.NotLoaded{} | LifecycleTransaction.t() | nil,
l2_transactions: %Ecto.Association.NotLoaded{} | [BatchTransaction.t()]
}
@primary_key {:number, :integer, autogenerate: false}
schema "zkevm_transaction_batches" do
@primary_key false
typed_schema "zkevm_transaction_batches" do
field(:number, :integer, primary_key: true, null: false)
field(:timestamp, :utc_datetime_usec)
field(:l2_transactions_count, :integer)
field(:global_exit_root, Hash.Full)
@ -40,7 +27,7 @@ defmodule Explorer.Chain.Zkevm.TransactionBatch do
belongs_to(:verify_transaction, LifecycleTransaction, foreign_key: :verify_id, references: :id, type: :integer)
has_many(:l2_transactions, BatchTransaction, foreign_key: :batch_number)
has_many(:l2_transactions, BatchTransaction, foreign_key: :batch_number, references: :number)
timestamps()
end

@ -3,19 +3,13 @@ defmodule Explorer.Counters.LastFetchedCounter do
Stores last fetched counters.
"""
alias Explorer.Counters.LastFetchedCounter
use Explorer.Schema
import Ecto.Changeset
@type t :: %LastFetchedCounter{
counter_type: String.t(),
value: Decimal.t()
}
@primary_key false
schema "last_fetched_counters" do
field(:counter_type, :string)
typed_schema "last_fetched_counters" do
field(:counter_type, :string, null: false)
field(:value, :decimal)
timestamps()

@ -2,4 +2,6 @@ defmodule Explorer.Encrypted.AddressHash do
@moduledoc false
use Explorer.Encrypted.Types.AddressHash, vault: Explorer.Vault
@type t :: Explorer.Chain.Hash.Address.t()
end

@ -2,4 +2,6 @@ defmodule Explorer.Encrypted.Binary do
@moduledoc false
use Cloak.Ecto.Binary, vault: Explorer.Vault
@type t :: binary()
end

@ -2,4 +2,6 @@ defmodule Explorer.Encrypted.TransactionHash do
@moduledoc false
use Explorer.Encrypted.Types.TransactionHash, vault: Explorer.Vault
@type t :: Explorer.Chain.Hash.Full.t()
end

@ -5,14 +5,6 @@ defmodule Explorer.Market.MarketHistory do
use Explorer.Schema
schema "market_history" do
field(:closing_price, :decimal)
field(:date, :date)
field(:opening_price, :decimal)
field(:market_cap, :decimal)
field(:tvl, :decimal)
end
@typedoc """
The recorded values of the configured coin to USD for a single day.
@ -22,11 +14,11 @@ defmodule Explorer.Market.MarketHistory do
* `:market_cap` - Market cap in USD.
* `:tvl` - TVL in USD.
"""
@type t :: %__MODULE__{
closing_price: Decimal.t() | nil,
date: Date.t(),
opening_price: Decimal.t() | nil,
market_cap: Decimal.t() | nil,
tvl: Decimal.t() | nil
}
typed_schema "market_history" do
field(:closing_price, :decimal)
field(:date, :date, null: false)
field(:opening_price, :decimal)
field(:market_cap, :decimal)
field(:tvl, :decimal)
end
end

@ -7,7 +7,7 @@ defmodule Explorer.Migrator.MigrationStatus do
alias Explorer.Repo
@primary_key false
schema "migrations_status" do
typed_schema "migrations_status" do
field(:migration_name, :string)
# ["started", "completed"]
field(:status, :string)

@ -3,7 +3,7 @@ defmodule Explorer.Schema do
defmacro __using__(_opts) do
quote do
use Ecto.Schema
use TypedEctoSchema
import Ecto.{Changeset, Query}

@ -20,13 +20,9 @@ defmodule Explorer.Tags.AddressTag do
* `:label` - Tag's label
* `:display_name` - Label's display name
"""
@type t :: %AddressTag{
label: String.t()
}
schema "address_tags" do
field(:label, :string)
field(:display_name, :string)
typed_schema "address_tags" do
field(:label, :string, null: false)
field(:display_name, :string, null: false)
has_many(:tag_id, AddressToTag, foreign_key: :id)
timestamps()

@ -17,18 +17,14 @@ defmodule Explorer.Tags.AddressToTag do
* `:tag_id` - id of Tag
* `:address_hash` - hash of Address
"""
@type t :: %AddressToTag{
tag_id: Decimal.t(),
address_hash: Hash.Address.t()
}
schema "address_to_tags" do
typed_schema "address_to_tags" do
belongs_to(
:tag,
AddressTag,
foreign_key: :tag_id,
references: :id,
type: :integer
type: :integer,
null: false
)
belongs_to(
@ -36,7 +32,8 @@ defmodule Explorer.Tags.AddressToTag do
Address,
foreign_key: :address_hash,
references: :hash,
type: Hash.Address
type: Hash.Address,
null: false
)
timestamps()

@ -5,7 +5,7 @@ defmodule Explorer.Utility.EventNotification do
use Explorer.Schema
schema "event_notifications" do
typed_schema "event_notifications" do
field(:data, :string)
end

@ -8,7 +8,7 @@ defmodule Explorer.Utility.MissingBlockRange do
@default_returning_batch_size 10
schema "missing_block_ranges" do
typed_schema "missing_block_ranges" do
field(:from_number, :integer)
field(:to_number, :integer)
end

@ -118,7 +118,8 @@ defmodule Explorer.Mixfile do
{:cloak_ecto, "~> 1.2.0"},
{:redix, "~> 1.1"},
{:hammer_backend_redis, "~> 6.1"},
{:logger_json, "~> 5.1"}
{:logger_json, "~> 5.1"},
{:typed_ecto_schema, "~> 0.4.1", runtime: false}
]
end

@ -135,6 +135,7 @@
"tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"toml": {:hex, :toml, "0.6.2", "38f445df384a17e5d382befe30e3489112a48d3ba4c459e543f748c2f25dd4d1", [:mix], [], "hexpm", "d013e45126d74c0c26a38d31f5e8e9b83ea19fc752470feb9a86071ca5a672fa"},
"typed_ecto_schema": {:hex, :typed_ecto_schema, "0.4.1", "a373ca6f693f4de84cde474a67467a9cb9051a8a7f3f615f1e23dc74b75237fa", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "85c6962f79d35bf543dd5659c6adc340fd2480cacc6f25d2cc2933ea6e8fcb3b"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"ueberauth": {:hex, :ueberauth, "0.10.7", "5a31cbe11e7ce5c7484d745dc9e1f11948e89662f8510d03c616de03df581ebd", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "0bccf73e2ffd6337971340832947ba232877aa8122dba4c95be9f729c8987377"},
"ueberauth_auth0": {:hex, :ueberauth_auth0, "2.1.0", "0632d5844049fa2f26823f15e1120aa32f27df6f27ce515a4b04641736594bf4", [:mix], [{:oauth2, "~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "8d3b30fa27c95c9e82c30c4afb016251405706d2e9627e603c3c9787fd1314fc"},

Loading…
Cancel
Save