diff --git a/.dialyzer-ignore b/.dialyzer-ignore
index 1535f582c8..79833b82e3 100644
--- a/.dialyzer-ignore
+++ b/.dialyzer-ignore
@@ -12,4 +12,6 @@ apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The pattern 'fa
apps/explorer/lib/explorer/smart_contract/publisher_worker.ex:6: The test 5 == 'infinity' can never evaluate to 'true'
lib/block_scout_web/router.ex:1
lib/phoenix/router.ex:324
-lib/block_scout_web/views/layout_view.ex:143
\ No newline at end of file
+lib/block_scout_web/views/layout_view.ex:143
+lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:21
+lib/block_scout_web/controllers/api/rpc/transaction_controller.ex:22
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 287e54992b..5371ca264f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,44 @@
## Current
### Features
+- [#3149](https://github.com/poanetwork/blockscout/pull/3149) - Display and store revert reason of tx on demand at transaction details page and at gettxinfo API endpoint.
### Fixes
### Chore
+- [#3152](https://github.com/poanetwork/blockscout/pull/3152) - Fix contract compilation tests for old versions of compiler
+
+
+## 3.1.3-beta
+
+### Features
+- [#3125](https://github.com/poanetwork/blockscout/pull/3125) - Availability to configure a number of days to consider at coin balance history chart via environment variable
+
+### Fixes
+- [#3146](https://github.com/poanetwork/blockscout/pull/3146) - Fix coin balance history page: order of items, fix if no balance changes
+- [#3142](https://github.com/poanetwork/blockscout/pull/3142) - Speed-up last coin balance timestamp query (coin balance history page performance improvement)
+- [#3140](https://github.com/poanetwork/blockscout/pull/3140) - Fix performance of the balance changing history list loading
+- [#3133](https://github.com/poanetwork/blockscout/pull/3133) - Take into account FIRST_BLOCK in trace_ReplayBlockTransactions requests
+- [#3132](https://github.com/poanetwork/blockscout/pull/3132) - Fix performance of coin supply API endpoints
+- [#3130](https://github.com/poanetwork/blockscout/pull/3130) - Take into account FIRST_BLOCK for block rewards fetching
+- [#3128](https://github.com/poanetwork/blockscout/pull/3128) - Token instance metadata retriever refinement: add processing of token metadata if only image URL is passed to token URI
+- [#3126](https://github.com/poanetwork/blockscout/pull/3126) - Fetch balance only for blocks which are greater or equal block with FIRST_BLOCK number
+- [#3125](https://github.com/poanetwork/blockscout/pull/3125) - Fix performance of coin balance history chart
+- [#3122](https://github.com/poanetwork/blockscout/pull/3122) - Exclude balance percentage calculation for burn address on accounts page
+- [#3121](https://github.com/poanetwork/blockscout/pull/3121) - Geth: handle response from eth_getblockbyhash JSON RPC method without totalDifficulty (uncle blocks)
+- [#3119](https://github.com/poanetwork/blockscout/pull/3119), [#3120](https://github.com/poanetwork/blockscout/pull/3120) - Fix performance of Inventory tab loading for ERC-721 tokens
+- [#3114](https://github.com/poanetwork/blockscout/pull/3114) - Fix performance of "Blocks validated" page
+- [#3112](https://github.com/poanetwork/blockscout/pull/3112) - Fix verification of contracts, compiled with nightly builds of solc compiler
+- [#3112](https://github.com/poanetwork/blockscout/pull/3112) - Check compiler version at contract verification
+- [#3106](https://github.com/poanetwork/blockscout/pull/3106) - Fix verification of contracts with `immutable` declaration
+- [#3106](https://github.com/poanetwork/blockscout/pull/3106), [#3115](https://github.com/poanetwork/blockscout/pull/3115) - Fix verification of contracts, created from factory (from internal transaction)
+
+### Chore
+- [#3137](https://github.com/poanetwork/blockscout/pull/3137) - RSK Papyrus Release v2.0.1 hardfork: cumulativeDifficulty
+- [#3134](https://github.com/poanetwork/blockscout/pull/3134) - Get last value of fetched coinsupply API endpoint from DB if cache is empty
+- [#3124](https://github.com/poanetwork/blockscout/pull/3124) - Display upper border for tx speed if the value cannot be calculated
+
## 3.1.2-beta
diff --git a/apps/block_scout_web/config/config.exs b/apps/block_scout_web/config/config.exs
index 9fd1da1f08..b5bd4087f6 100644
--- a/apps/block_scout_web/config/config.exs
+++ b/apps/block_scout_web/config/config.exs
@@ -84,6 +84,10 @@ config :block_scout_web, BlockScoutWeb.Chain.TransactionHistoryChartController,
# days
history_size: 30
+config :block_scout_web, BlockScoutWeb.Chain.Address.CoinBalance,
+ # days
+ coin_balance_history_days: System.get_env("COIN_BALANCE_HISTORY_DAYS", "10")
+
config :ex_cldr,
default_locale: "en",
default_backend: BlockScoutWeb.Cldr
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/stats_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/stats_controller.ex
index 7a1920b790..be8230145b 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/stats_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/stats_controller.ex
@@ -44,8 +44,15 @@ defmodule BlockScoutWeb.API.RPC.StatsController do
def coinsupply(conn, _params) do
cached_coin_total_supply_wei = AddressSumMinusBurnt.get_sum_minus_burnt()
+ coin_total_supply_wei =
+ if Decimal.cmp(cached_coin_total_supply_wei, 0) == :gt do
+ cached_coin_total_supply_wei
+ else
+ Chain.get_last_fetched_counter("sum_coin_total_supply_minus_burnt")
+ end
+
cached_coin_total_supply =
- %Wei{value: Decimal.new(cached_coin_total_supply_wei)}
+ %Wei{value: Decimal.new(coin_total_supply_wei)}
|> Wei.to(:ether)
render(conn, "coinsupply.json", cached_coin_total_supply)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
index 565ea4b6a5..4c7abad3fe 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
@@ -5,16 +5,30 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do
alias Explorer.Chain
+ alias Explorer.Chain.Transaction
+
def gettxinfo(conn, params) do
with {:txhash_param, {:ok, txhash_param}} <- fetch_txhash(params),
{:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param),
- {:transaction, {:ok, transaction}} <- transaction_from_hash(transaction_hash),
+ {:transaction, {:ok, %Transaction{revert_reason: revert_reason, error: error} = transaction}} <-
+ transaction_from_hash(transaction_hash),
paging_options <- paging_options(params) do
logs = Chain.transaction_to_logs(transaction_hash, paging_options)
{logs, next_page} = split_list_by_page(logs)
+ transaction_updated =
+ if error == "Reverted" do
+ if revert_reason == nil do
+ %Transaction{transaction | revert_reason: Chain.fetch_tx_revert_reason(transaction)}
+ else
+ transaction
+ end
+ else
+ transaction
+ end
+
render(conn, :gettxinfo, %{
- transaction: transaction,
+ transaction: transaction_updated,
block_height: Chain.block_height(),
logs: logs,
next_page_params: next_page_params(next_page, logs, params)
diff --git a/apps/block_scout_web/lib/block_scout_web/etherscan.ex b/apps/block_scout_web/lib/block_scout_web/etherscan.ex
index 019795dc69..f419f05eee 100644
--- a/apps/block_scout_web/lib/block_scout_web/etherscan.ex
+++ b/apps/block_scout_web/lib/block_scout_web/etherscan.ex
@@ -470,7 +470,8 @@ defmodule BlockScoutWeb.Etherscan do
"success" => true,
"timeStamp" => "1541018182",
"to" => "0x000000000000000000000000000000000000000d",
- "value" => "67612"
+ "value" => "67612",
+ revertReason: "No credit of that type"
}
}
@@ -609,6 +610,12 @@ defmodule BlockScoutWeb.Etherscan do
example: ~s("18")
}
+ @revert_reason_type %{
+ type: "revert_reason",
+ definition: "Revert reason of transaction.",
+ example: ~s("No credit of that type")
+ }
+
@logs_details %{
name: "Log Detail",
fields: %{
@@ -1010,7 +1017,8 @@ defmodule BlockScoutWeb.Etherscan do
logs: %{
type: "array",
array_type: @logs_details
- }
+ },
+ revertReason: @revert_reason_type
}
}
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
index cca53f0865..5ee1fac85e 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/overview.html.eex
@@ -53,6 +53,14 @@
+ <%= if status == {:error, "Reverted"} do %>
+
+ - <%= gettext "Revert reason" %>
+ -
+ <%= BlockScoutWeb.TransactionView.transaction_revert_reason(@transaction) %>
+
+
+ <% end %>
- <%= gettext "Block Number" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex
index 3e536bb0b3..1b14c7b424 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex
@@ -116,6 +116,17 @@ defmodule BlockScoutWeb.AddressView do
def balance_percentage(_, nil), do: ""
+ def balance_percentage(
+ %Address{
+ hash: %Explorer.Chain.Hash{
+ byte_count: 20,
+ bytes: <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>
+ }
+ },
+ _
+ ),
+ do: ""
+
def balance_percentage(%Address{fetched_coin_balance: balance}, total_supply) do
if total_supply > 0 do
balance
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex
index b9e8f7430d..4b81b11091 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/rpc/transaction_view.ex
@@ -70,6 +70,7 @@ defmodule BlockScoutWeb.API.RPC.TransactionView do
"gasUsed" => "#{transaction.gas_used}",
"gasPrice" => "#{transaction.gas_price.value}",
"logs" => Enum.map(logs, &prepare_log/1),
+ "revertReason" => "#{transaction.revert_reason}",
"next_page_params" => next_page_params
}
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex b/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex
index 02937fec9f..ab0058f4a8 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/tokens/instance/overview_view.ex
@@ -26,7 +26,7 @@ defmodule BlockScoutWeb.Tokens.Instance.OverviewView do
instance.metadata["image_url"]
instance.metadata && instance.metadata["image"] ->
- instance.metadata["image"]
+ retrieve_image(instance.metadata["image"])
instance.metadata && instance.metadata["properties"]["image"]["description"] ->
instance.metadata["properties"]["image"]["description"]
@@ -87,6 +87,14 @@ defmodule BlockScoutWeb.Tokens.Instance.OverviewView do
|> tab_name()
end
+ defp retrieve_image(image) when is_map(image) do
+ image["description"]
+ end
+
+ defp retrieve_image(image) do
+ image
+ end
+
defp tab_name(["token_transfers"]), do: gettext("Token Transfers")
defp tab_name(["metadata"]), do: gettext("Metadata")
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex
index 252df60bf5..c128083916 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/transaction_view.ex
@@ -6,6 +6,7 @@ defmodule BlockScoutWeb.TransactionView do
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block.Reward
alias Explorer.Chain.{Address, Block, InternalTransaction, Transaction, Wei}
+ alias Explorer.Counters.AverageBlockTime
alias Explorer.ExchangeRates.Token
alias Timex.Duration
@@ -144,7 +145,17 @@ defmodule BlockScoutWeb.TransactionView do
end
def processing_time_duration(%Transaction{earliest_processing_start: nil}) do
- :unknown
+ avg_time = AverageBlockTime.average_block_time()
+
+ if avg_time == {:error, :disabled} do
+ :unknown
+ else
+ avg_time_in_secs =
+ avg_time
+ |> Duration.to_seconds()
+
+ {:ok, "<= #{avg_time_in_secs} seconds"}
+ end
end
def processing_time_duration(%Transaction{
@@ -226,6 +237,10 @@ defmodule BlockScoutWeb.TransactionView do
Chain.transaction_to_status(transaction)
end
+ def transaction_revert_reason(transaction) do
+ Chain.transaction_to_revert_reason(transaction)
+ end
+
def empty_exchange_rate?(exchange_rate) do
Token.null?(exchange_rate)
end
diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs
index 234d21f0b1..39077461d0 100644
--- a/apps/block_scout_web/mix.exs
+++ b/apps/block_scout_web/mix.exs
@@ -90,7 +90,7 @@ defmodule BlockScoutWeb.Mixfile do
{:floki, "~> 0.20.1", only: :test},
{:flow, "~> 0.12"},
{:gettext, "~> 0.16.1"},
- {:httpoison, "~> 1.0"},
+ {:httpoison, "~> 1.6"},
{:indexer, in_umbrella: true, runtime: false},
# JSON parser and generator
{:jason, "~> 1.0"},
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index de30d52252..9157634e2c 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -13,7 +13,7 @@ msgstr[0] ""
msgstr[1] ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:196
+#: lib/block_scout_web/templates/transaction/overview.html.eex:204
msgid " Token Transfer"
msgstr ""
@@ -59,7 +59,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:236
+#: lib/block_scout_web/views/transaction_view.ex:251
msgid "(Awaiting internal transactions for status)"
msgstr ""
@@ -193,7 +193,7 @@ msgid "Block %{block_number} - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:72
+#: lib/block_scout_web/templates/transaction/overview.html.eex:80
msgid "Block Confirmations"
msgstr ""
@@ -213,12 +213,12 @@ msgid "Block Mined, awaiting import..."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:58
+#: lib/block_scout_web/templates/transaction/overview.html.eex:66
msgid "Block Number"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:32
+#: lib/block_scout_web/views/transaction_view.ex:33
msgid "Block Pending"
msgstr ""
@@ -355,12 +355,12 @@ msgid "Contract Byte Code"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:325
+#: lib/block_scout_web/views/transaction_view.ex:340
msgid "Contract Call"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:322
+#: lib/block_scout_web/views/transaction_view.ex:337
msgid "Contract Creation"
msgstr ""
@@ -558,12 +558,12 @@ msgid "During times when the network is busy (i.e during ICOs) it can take a whi
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:136
+#: lib/block_scout_web/views/transaction_view.ex:137
msgid "ERC-20 "
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:137
+#: lib/block_scout_web/views/transaction_view.ex:138
msgid "ERC-721 "
msgstr ""
@@ -621,12 +621,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:240
+#: lib/block_scout_web/views/transaction_view.ex:255
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:238
+#: lib/block_scout_web/views/transaction_view.ex:253
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@@ -646,8 +646,8 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:32
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:29
-#: lib/block_scout_web/templates/transaction/overview.html.eex:181
-#: lib/block_scout_web/templates/transaction/overview.html.eex:255
+#: lib/block_scout_web/templates/transaction/overview.html.eex:189
+#: lib/block_scout_web/templates/transaction/overview.html.eex:263
#: lib/block_scout_web/views/wei_helpers.ex:78
msgid "Ether"
msgstr ""
@@ -666,7 +666,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:73
-#: lib/block_scout_web/templates/transaction/overview.html.eex:79
+#: lib/block_scout_web/templates/transaction/overview.html.eex:87
msgid "Nonce"
msgstr ""
@@ -753,8 +753,8 @@ msgid "Hash"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:115
-#: lib/block_scout_web/templates/transaction/overview.html.eex:119
+#: lib/block_scout_web/templates/transaction/overview.html.eex:123
+#: lib/block_scout_web/templates/transaction/overview.html.eex:127
msgid "Hex (Default)"
msgstr ""
@@ -776,7 +776,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
-#: lib/block_scout_web/views/transaction_view.ex:237
+#: lib/block_scout_web/views/transaction_view.ex:252
msgid "Success"
msgstr ""
@@ -789,7 +789,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:21
#: lib/block_scout_web/templates/transaction/_tile.html.eex:32
-#: lib/block_scout_web/templates/transaction/overview.html.eex:84
+#: lib/block_scout_web/templates/transaction/overview.html.eex:92
msgid "TX Fee"
msgstr ""
@@ -891,7 +891,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:12
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:10
-#: lib/block_scout_web/views/transaction_view.ex:318
+#: lib/block_scout_web/views/transaction_view.ex:333
msgid "Token Transfer"
msgstr ""
@@ -903,10 +903,10 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:14
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
-#: lib/block_scout_web/views/address_view.ex:314
-#: lib/block_scout_web/views/tokens/instance/overview_view.ex:90
+#: lib/block_scout_web/views/address_view.ex:325
+#: lib/block_scout_web/views/tokens/instance/overview_view.ex:98
#: lib/block_scout_web/views/tokens/overview_view.ex:35
-#: lib/block_scout_web/views/transaction_view.ex:379
+#: lib/block_scout_web/views/transaction_view.ex:394
msgid "Token Transfers"
msgstr ""
@@ -922,7 +922,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:18
-#: lib/block_scout_web/views/transaction_view.ex:328
+#: lib/block_scout_web/views/transaction_view.ex:343
msgid "Transaction"
msgstr ""
@@ -1005,7 +1005,7 @@ msgid "License ID"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:283
+#: lib/block_scout_web/templates/transaction/overview.html.eex:291
msgid "Limit"
msgstr ""
@@ -1041,12 +1041,12 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:52
#: lib/block_scout_web/templates/layout/app.html.eex:30
-#: lib/block_scout_web/views/address_view.ex:127
+#: lib/block_scout_web/views/address_view.ex:138
msgid "Market Cap"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:221
+#: lib/block_scout_web/views/transaction_view.ex:232
msgid "Max of"
msgstr ""
@@ -1159,8 +1159,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:59
-#: lib/block_scout_web/views/transaction_view.ex:235
-#: lib/block_scout_web/views/transaction_view.ex:269
+#: lib/block_scout_web/views/transaction_view.ex:250
+#: lib/block_scout_web/views/transaction_view.ex:284
msgid "Pending"
msgstr ""
@@ -1201,14 +1201,14 @@ msgid "RPC"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:109
+#: lib/block_scout_web/templates/transaction/overview.html.eex:117
msgid "Raw Input"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:24
#: lib/block_scout_web/templates/transaction_raw_trace/index.html.eex:7
-#: lib/block_scout_web/views/transaction_view.ex:382
+#: lib/block_scout_web/views/transaction_view.ex:397
msgid "Raw Trace"
msgstr ""
@@ -1488,7 +1488,7 @@ msgid "Transaction Inputs"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:101
+#: lib/block_scout_web/templates/transaction/overview.html.eex:109
msgid "Transaction Speed"
msgstr ""
@@ -1518,7 +1518,7 @@ msgid "Type"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:122
+#: lib/block_scout_web/templates/transaction/overview.html.eex:130
msgid "UTF-8"
msgstr ""
@@ -1544,7 +1544,7 @@ msgid "Use the search box to find a hosted network, or select from the list of a
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:277
+#: lib/block_scout_web/templates/transaction/overview.html.eex:285
msgid "Used"
msgstr ""
@@ -1574,8 +1574,8 @@ msgid "Validator Info"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:181
-#: lib/block_scout_web/templates/transaction/overview.html.eex:255
+#: lib/block_scout_web/templates/transaction/overview.html.eex:189
+#: lib/block_scout_web/templates/transaction/overview.html.eex:263
msgid "Value"
msgstr ""
@@ -1752,7 +1752,7 @@ msgid "Decimals"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:273
+#: lib/block_scout_web/templates/transaction/overview.html.eex:281
msgid "Gas"
msgstr ""
@@ -1779,7 +1779,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/metadata/index.html.eex:18
#: lib/block_scout_web/templates/tokens/instance/overview/_tabs.html.eex:10
-#: lib/block_scout_web/views/tokens/instance/overview_view.ex:91
+#: lib/block_scout_web/views/tokens/instance/overview_view.ex:99
msgid "Metadata"
msgstr ""
@@ -1799,15 +1799,15 @@ msgid "Transfers"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:134
-#: lib/block_scout_web/templates/transaction/overview.html.eex:147
+#: lib/block_scout_web/templates/transaction/overview.html.eex:142
+#: lib/block_scout_web/templates/transaction/overview.html.eex:155
msgid "Copy Txn Input"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:37
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
-#: lib/block_scout_web/views/address_view.ex:319
+#: lib/block_scout_web/views/address_view.ex:330
msgid "Blocks Validated"
msgstr ""
@@ -1817,18 +1817,18 @@ msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
-#: lib/block_scout_web/views/address_view.ex:315
+#: lib/block_scout_web/views/address_view.ex:326
msgid "Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:26
-#: lib/block_scout_web/views/address_view.ex:318
+#: lib/block_scout_web/views/address_view.ex:329
msgid "Coin Balance History"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/address_view.ex:316
+#: lib/block_scout_web/views/address_view.ex:327
msgid "Decompiled Code"
msgstr ""
@@ -1837,8 +1837,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:19
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
-#: lib/block_scout_web/views/address_view.ex:313
-#: lib/block_scout_web/views/transaction_view.ex:380
+#: lib/block_scout_web/views/address_view.ex:324
+#: lib/block_scout_web/views/transaction_view.ex:395
msgid "Internal Transactions"
msgstr ""
@@ -1847,15 +1847,15 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:8
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
-#: lib/block_scout_web/views/address_view.ex:320
-#: lib/block_scout_web/views/transaction_view.ex:381
+#: lib/block_scout_web/views/address_view.ex:331
+#: lib/block_scout_web/views/transaction_view.ex:396
msgid "Logs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:62
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:25
-#: lib/block_scout_web/views/address_view.ex:317
+#: lib/block_scout_web/views/address_view.ex:328
#: lib/block_scout_web/views/tokens/overview_view.ex:37
msgid "Read Contract"
msgstr ""
@@ -1864,7 +1864,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:14
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:11
-#: lib/block_scout_web/views/address_view.ex:311
+#: lib/block_scout_web/views/address_view.ex:322
msgid "Tokens"
msgstr ""
@@ -1876,31 +1876,31 @@ msgstr ""
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:184
#: lib/block_scout_web/templates/layout/_topnav.html.eex:50
-#: lib/block_scout_web/views/address_view.ex:312
+#: lib/block_scout_web/views/address_view.ex:323
msgid "Transactions"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:232
+#: lib/block_scout_web/templates/transaction/overview.html.eex:240
msgid " Token Burning"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:8
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:6
-#: lib/block_scout_web/views/transaction_view.ex:317
+#: lib/block_scout_web/views/transaction_view.ex:332
msgid "Token Burning"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:214
+#: lib/block_scout_web/templates/transaction/overview.html.eex:222
msgid " Token Minting"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:10
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:8
-#: lib/block_scout_web/views/transaction_view.ex:316
+#: lib/block_scout_web/views/transaction_view.ex:331
msgid "Token Minting"
msgstr ""
@@ -1908,3 +1908,8 @@ msgstr ""
#: lib/block_scout_web/views/block_view.ex:62
msgid "Chore Reward"
msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/overview.html.eex:58
+msgid "Revert reason"
+msgstr ""
diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
index de30d52252..9157634e2c 100644
--- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -13,7 +13,7 @@ msgstr[0] ""
msgstr[1] ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:196
+#: lib/block_scout_web/templates/transaction/overview.html.eex:204
msgid " Token Transfer"
msgstr ""
@@ -59,7 +59,7 @@ msgid "%{subnetwork} Explorer - BlockScout"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:236
+#: lib/block_scout_web/views/transaction_view.ex:251
msgid "(Awaiting internal transactions for status)"
msgstr ""
@@ -193,7 +193,7 @@ msgid "Block %{block_number} - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:72
+#: lib/block_scout_web/templates/transaction/overview.html.eex:80
msgid "Block Confirmations"
msgstr ""
@@ -213,12 +213,12 @@ msgid "Block Mined, awaiting import..."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:58
+#: lib/block_scout_web/templates/transaction/overview.html.eex:66
msgid "Block Number"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:32
+#: lib/block_scout_web/views/transaction_view.ex:33
msgid "Block Pending"
msgstr ""
@@ -355,12 +355,12 @@ msgid "Contract Byte Code"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:325
+#: lib/block_scout_web/views/transaction_view.ex:340
msgid "Contract Call"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:322
+#: lib/block_scout_web/views/transaction_view.ex:337
msgid "Contract Creation"
msgstr ""
@@ -558,12 +558,12 @@ msgid "During times when the network is busy (i.e during ICOs) it can take a whi
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:136
+#: lib/block_scout_web/views/transaction_view.ex:137
msgid "ERC-20 "
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:137
+#: lib/block_scout_web/views/transaction_view.ex:138
msgid "ERC-721 "
msgstr ""
@@ -621,12 +621,12 @@ msgid "Error trying to fetch balances."
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:240
+#: lib/block_scout_web/views/transaction_view.ex:255
msgid "Error: %{reason}"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:238
+#: lib/block_scout_web/views/transaction_view.ex:253
msgid "Error: (Awaiting internal transactions for reason)"
msgstr ""
@@ -646,8 +646,8 @@ msgstr ""
#: lib/block_scout_web/templates/layout/app.html.eex:32
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:29
-#: lib/block_scout_web/templates/transaction/overview.html.eex:181
-#: lib/block_scout_web/templates/transaction/overview.html.eex:255
+#: lib/block_scout_web/templates/transaction/overview.html.eex:189
+#: lib/block_scout_web/templates/transaction/overview.html.eex:263
#: lib/block_scout_web/views/wei_helpers.ex:78
msgid "Ether"
msgstr ""
@@ -666,7 +666,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:73
-#: lib/block_scout_web/templates/transaction/overview.html.eex:79
+#: lib/block_scout_web/templates/transaction/overview.html.eex:87
msgid "Nonce"
msgstr ""
@@ -753,8 +753,8 @@ msgid "Hash"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:115
-#: lib/block_scout_web/templates/transaction/overview.html.eex:119
+#: lib/block_scout_web/templates/transaction/overview.html.eex:123
+#: lib/block_scout_web/templates/transaction/overview.html.eex:127
msgid "Hex (Default)"
msgstr ""
@@ -776,7 +776,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_emission_reward_tile.html.eex:8
-#: lib/block_scout_web/views/transaction_view.ex:237
+#: lib/block_scout_web/views/transaction_view.ex:252
msgid "Success"
msgstr ""
@@ -789,7 +789,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:21
#: lib/block_scout_web/templates/transaction/_tile.html.eex:32
-#: lib/block_scout_web/templates/transaction/overview.html.eex:84
+#: lib/block_scout_web/templates/transaction/overview.html.eex:92
msgid "TX Fee"
msgstr ""
@@ -891,7 +891,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:12
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:10
-#: lib/block_scout_web/views/transaction_view.ex:318
+#: lib/block_scout_web/views/transaction_view.ex:333
msgid "Token Transfer"
msgstr ""
@@ -903,10 +903,10 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:14
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
-#: lib/block_scout_web/views/address_view.ex:314
-#: lib/block_scout_web/views/tokens/instance/overview_view.ex:90
+#: lib/block_scout_web/views/address_view.ex:325
+#: lib/block_scout_web/views/tokens/instance/overview_view.ex:98
#: lib/block_scout_web/views/tokens/overview_view.ex:35
-#: lib/block_scout_web/views/transaction_view.ex:379
+#: lib/block_scout_web/views/transaction_view.ex:394
msgid "Token Transfers"
msgstr ""
@@ -922,7 +922,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:18
-#: lib/block_scout_web/views/transaction_view.ex:328
+#: lib/block_scout_web/views/transaction_view.ex:343
msgid "Transaction"
msgstr ""
@@ -1005,7 +1005,7 @@ msgid "License ID"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:283
+#: lib/block_scout_web/templates/transaction/overview.html.eex:291
msgid "Limit"
msgstr ""
@@ -1041,12 +1041,12 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:52
#: lib/block_scout_web/templates/layout/app.html.eex:30
-#: lib/block_scout_web/views/address_view.ex:127
+#: lib/block_scout_web/views/address_view.ex:138
msgid "Market Cap"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/transaction_view.ex:221
+#: lib/block_scout_web/views/transaction_view.ex:232
msgid "Max of"
msgstr ""
@@ -1159,8 +1159,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:59
-#: lib/block_scout_web/views/transaction_view.ex:235
-#: lib/block_scout_web/views/transaction_view.ex:269
+#: lib/block_scout_web/views/transaction_view.ex:250
+#: lib/block_scout_web/views/transaction_view.ex:284
msgid "Pending"
msgstr ""
@@ -1201,14 +1201,14 @@ msgid "RPC"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:109
+#: lib/block_scout_web/templates/transaction/overview.html.eex:117
msgid "Raw Input"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:24
#: lib/block_scout_web/templates/transaction_raw_trace/index.html.eex:7
-#: lib/block_scout_web/views/transaction_view.ex:382
+#: lib/block_scout_web/views/transaction_view.ex:397
msgid "Raw Trace"
msgstr ""
@@ -1488,7 +1488,7 @@ msgid "Transaction Inputs"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:101
+#: lib/block_scout_web/templates/transaction/overview.html.eex:109
msgid "Transaction Speed"
msgstr ""
@@ -1518,7 +1518,7 @@ msgid "Type"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:122
+#: lib/block_scout_web/templates/transaction/overview.html.eex:130
msgid "UTF-8"
msgstr ""
@@ -1544,7 +1544,7 @@ msgid "Use the search box to find a hosted network, or select from the list of a
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:277
+#: lib/block_scout_web/templates/transaction/overview.html.eex:285
msgid "Used"
msgstr ""
@@ -1574,8 +1574,8 @@ msgid "Validator Info"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:181
-#: lib/block_scout_web/templates/transaction/overview.html.eex:255
+#: lib/block_scout_web/templates/transaction/overview.html.eex:189
+#: lib/block_scout_web/templates/transaction/overview.html.eex:263
msgid "Value"
msgstr ""
@@ -1752,7 +1752,7 @@ msgid "Decimals"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:273
+#: lib/block_scout_web/templates/transaction/overview.html.eex:281
msgid "Gas"
msgstr ""
@@ -1779,7 +1779,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/instance/metadata/index.html.eex:18
#: lib/block_scout_web/templates/tokens/instance/overview/_tabs.html.eex:10
-#: lib/block_scout_web/views/tokens/instance/overview_view.ex:91
+#: lib/block_scout_web/views/tokens/instance/overview_view.ex:99
msgid "Metadata"
msgstr ""
@@ -1799,15 +1799,15 @@ msgid "Transfers"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:134
-#: lib/block_scout_web/templates/transaction/overview.html.eex:147
+#: lib/block_scout_web/templates/transaction/overview.html.eex:142
+#: lib/block_scout_web/templates/transaction/overview.html.eex:155
msgid "Copy Txn Input"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:37
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
-#: lib/block_scout_web/views/address_view.ex:319
+#: lib/block_scout_web/views/address_view.ex:330
msgid "Blocks Validated"
msgstr ""
@@ -1817,18 +1817,18 @@ msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
-#: lib/block_scout_web/views/address_view.ex:315
+#: lib/block_scout_web/views/address_view.ex:326
msgid "Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:26
-#: lib/block_scout_web/views/address_view.ex:318
+#: lib/block_scout_web/views/address_view.ex:329
msgid "Coin Balance History"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/views/address_view.ex:316
+#: lib/block_scout_web/views/address_view.ex:327
msgid "Decompiled Code"
msgstr ""
@@ -1837,8 +1837,8 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:19
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
-#: lib/block_scout_web/views/address_view.ex:313
-#: lib/block_scout_web/views/transaction_view.ex:380
+#: lib/block_scout_web/views/address_view.ex:324
+#: lib/block_scout_web/views/transaction_view.ex:395
msgid "Internal Transactions"
msgstr ""
@@ -1847,15 +1847,15 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:8
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
-#: lib/block_scout_web/views/address_view.ex:320
-#: lib/block_scout_web/views/transaction_view.ex:381
+#: lib/block_scout_web/views/address_view.ex:331
+#: lib/block_scout_web/views/transaction_view.ex:396
msgid "Logs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:62
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:25
-#: lib/block_scout_web/views/address_view.ex:317
+#: lib/block_scout_web/views/address_view.ex:328
#: lib/block_scout_web/views/tokens/overview_view.ex:37
msgid "Read Contract"
msgstr ""
@@ -1864,7 +1864,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:14
#: lib/block_scout_web/templates/address_token/index.html.eex:8
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:11
-#: lib/block_scout_web/views/address_view.ex:311
+#: lib/block_scout_web/views/address_view.ex:322
msgid "Tokens"
msgstr ""
@@ -1876,31 +1876,31 @@ msgstr ""
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:184
#: lib/block_scout_web/templates/layout/_topnav.html.eex:50
-#: lib/block_scout_web/views/address_view.ex:312
+#: lib/block_scout_web/views/address_view.ex:323
msgid "Transactions"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:232
+#: lib/block_scout_web/templates/transaction/overview.html.eex:240
msgid " Token Burning"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:8
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:6
-#: lib/block_scout_web/views/transaction_view.ex:317
+#: lib/block_scout_web/views/transaction_view.ex:332
msgid "Token Burning"
msgstr ""
#, elixir-format
-#: lib/block_scout_web/templates/transaction/overview.html.eex:214
+#: lib/block_scout_web/templates/transaction/overview.html.eex:222
msgid " Token Minting"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/tokens/transfer/_token_transfer.html.eex:10
#: lib/block_scout_web/templates/transaction_token_transfer/_token_transfer.html.eex:8
-#: lib/block_scout_web/views/transaction_view.ex:316
+#: lib/block_scout_web/views/transaction_view.ex:331
msgid "Token Minting"
msgstr ""
@@ -1908,3 +1908,8 @@ msgstr ""
#: lib/block_scout_web/views/block_view.ex:62
msgid "Chore Reward"
msgstr ""
+
+#, elixir-format
+#: lib/block_scout_web/templates/transaction/overview.html.eex:58
+msgid "Revert reason"
+msgstr ""
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_coin_balance_by_day_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_coin_balance_by_day_controller_test.exs
index 3778793300..8d94957b9c 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/address_coin_balance_by_day_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/address_coin_balance_by_day_controller_test.exs
@@ -11,6 +11,8 @@ defmodule BlockScoutWeb.AddressCoinBalanceByDayControllerTest do
block_one_day_ago = insert(:block, timestamp: Timex.shift(noon, days: -1), number: 1)
insert(:fetched_balance, address_hash: address.hash, value: 1000, block_number: block.number)
insert(:fetched_balance, address_hash: address.hash, value: 2000, block_number: block_one_day_ago.number)
+ insert(:fetched_balance_daily, address_hash: address.hash, value: 1000, day: noon)
+ insert(:fetched_balance_daily, address_hash: address.hash, value: 2000, day: Timex.shift(noon, days: -1))
conn = get(conn, address_coin_balance_by_day_path(conn, :index, Address.checksum(address)), %{"type" => "JSON"})
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs
index 1f18b5422d..5378ca6cfe 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/address_controller_test.exs
@@ -111,6 +111,30 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
address_hash = to_string(address.hash)
+ expect(EthereumJSONRPC.Mox, :json_rpc, 1, fn [
+ %{
+ id: id,
+ method: "eth_getBalance",
+ params: [^mining_address_hash, "0x65"]
+ }
+ ],
+ _options ->
+ {:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]}
+ end)
+
+ res = eth_block_number_fake_response("0x65")
+
+ expect(EthereumJSONRPC.Mox, :json_rpc, 1, fn [
+ %{
+ id: 0,
+ method: "eth_getBlockByNumber",
+ params: ["0x65", true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
expect(EthereumJSONRPC.Mox, :json_rpc, 1, fn [
%{
id: id,
@@ -122,6 +146,17 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]}
end)
+ expect(EthereumJSONRPC.Mox, :json_rpc, 1, fn [
+ %{
+ id: 0,
+ method: "eth_getBlockByNumber",
+ params: ["0x65", true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
response =
conn
|> get("/api", params)
@@ -2719,4 +2754,40 @@ defmodule BlockScoutWeb.API.RPC.AddressControllerTest do
|> put_in(["properties", "result"], result)
|> ExJsonSchema.Schema.resolve()
end
+
+ defp eth_block_number_fake_response(block_quantity) do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x0000000000000000000000000000000000000000",
+ "difficulty" => "0x20000",
+ "extraData" => "0x",
+ "gasLimit" => "0x663be0",
+ "gasUsed" => "0x0",
+ "hash" => "0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x0000000000000000000000000000000000000000",
+ "number" => block_quantity,
+ "parentHash" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x80",
+ "0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "size" => "0x215",
+ "stateRoot" => "0xfad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3",
+ "step" => "0",
+ "timestamp" => "0x0",
+ "totalDifficulty" => "0x20000",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ end
end
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
index b00d457426..98901ee5cd 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
@@ -609,6 +609,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
contract_code_info = Factory.contract_code_info()
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input)
params = %{
"module" => "contract",
@@ -658,10 +659,12 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
"name" => name,
"optimize" => optimize,
"contract" => contract_source_code,
- "expected_bytecode" => expected_bytecode
+ "expected_bytecode" => expected_bytecode,
+ "tx_input" => tx_input
} = contract_data
contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input)
params = %{
"module" => "contract",
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs
index 2b3f6fff5e..d46071d215 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/transaction_controller_test.exs
@@ -1,6 +1,8 @@
defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
use BlockScoutWeb.ConnCase
+ import Mox
+
@moduletag capture_log: true
describe "gettxreceiptstatus" do
@@ -520,7 +522,8 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
"index" => "#{log.index}"
}
],
- "next_page_params" => nil
+ "next_page_params" => nil,
+ "revertReason" => ""
}
schema =
@@ -576,6 +579,184 @@ defmodule BlockScoutWeb.API.RPC.TransactionControllerTest do
assert response["status"] == "1"
assert response["message"] == "OK"
end
+
+ test "with a txhash with revert reason from DB", %{conn: conn} do
+ block = insert(:block, number: 100)
+
+ transaction =
+ :transaction
+ |> insert(revert_reason: "No credit of that type")
+ |> with_block(block)
+
+ insert(:address)
+
+ params = %{
+ "module" => "transaction",
+ "action" => "gettxinfo",
+ "txhash" => "#{transaction.hash}"
+ }
+
+ assert response =
+ conn
+ |> get("/api", params)
+ |> json_response(200)
+
+ assert response["result"]["revertReason"] == "No credit of that type"
+ assert response["status"] == "1"
+ assert response["message"] == "OK"
+ end
+
+ test "with a txhash with empty revert reason from DB", %{conn: conn} do
+ block = insert(:block, number: 100)
+
+ transaction =
+ :transaction
+ |> insert(revert_reason: "")
+ |> with_block(block)
+
+ insert(:address)
+
+ params = %{
+ "module" => "transaction",
+ "action" => "gettxinfo",
+ "txhash" => "#{transaction.hash}"
+ }
+
+ assert response =
+ conn
+ |> get("/api", params)
+ |> json_response(200)
+
+ assert response["result"]["revertReason"] == ""
+ assert response["status"] == "1"
+ assert response["message"] == "OK"
+ end
+
+ test "with a txhash with revert reason from the archive node", %{conn: conn} do
+ block = insert(:block, number: 100, hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391")
+
+ transaction =
+ :transaction
+ |> insert(
+ error: "Reverted",
+ status: :error,
+ block_hash: block.hash,
+ block_number: block.number,
+ cumulative_gas_used: 884_322,
+ gas_used: 106_025,
+ index: 0,
+ hash: "0xac2a7dab94d965893199e7ee01649e2d66f0787a4c558b3118c09e80d4df8269"
+ )
+
+ insert(:address)
+
+ expect(
+ EthereumJSONRPC.Mox,
+ :json_rpc,
+ fn _json, [] ->
+ {:error, %{code: -32015, message: "VM execution error.", data: "revert: No credit of that type"}}
+ end
+ )
+
+ params = %{
+ "module" => "transaction",
+ "action" => "gettxinfo",
+ "txhash" => "#{transaction.hash}"
+ }
+
+ assert response =
+ conn
+ |> get("/api", params)
+ |> json_response(200)
+
+ assert response["result"]["revertReason"] == "No credit of that type"
+ assert response["status"] == "1"
+ assert response["message"] == "OK"
+ end
+ end
+
+ test "with a txhash with empty revert reason from the archive node", %{conn: conn} do
+ block = insert(:block, number: 100, hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391")
+
+ transaction =
+ :transaction
+ |> insert(
+ error: "Reverted",
+ status: :error,
+ block_hash: block.hash,
+ block_number: block.number,
+ cumulative_gas_used: 884_322,
+ gas_used: 106_025,
+ index: 0,
+ hash: "0xac2a7dab94d965893199e7ee01649e2d66f0787a4c558b3118c09e80d4df8269"
+ )
+
+ insert(:address)
+
+ expect(
+ EthereumJSONRPC.Mox,
+ :json_rpc,
+ fn _json, [] ->
+ {:error, %{code: -32015, message: "VM execution error.", data: ""}}
+ end
+ )
+
+ params = %{
+ "module" => "transaction",
+ "action" => "gettxinfo",
+ "txhash" => "#{transaction.hash}"
+ }
+
+ assert response =
+ conn
+ |> get("/api", params)
+ |> json_response(200)
+
+ assert response["result"]["revertReason"] == ""
+ assert response["status"] == "1"
+ assert response["message"] == "OK"
+ end
+
+ test "with a txhash with empty revert reason from DB if eth_call doesn't return an error", %{conn: conn} do
+ block = insert(:block, number: 100, hash: "0x3e51328bccedee581e8ba35190216a61a5d67fd91ca528f3553142c0c7d18391")
+
+ transaction =
+ :transaction
+ |> insert(
+ error: "Reverted",
+ status: :error,
+ block_hash: block.hash,
+ block_number: block.number,
+ cumulative_gas_used: 884_322,
+ gas_used: 106_025,
+ index: 0,
+ hash: "0xac2a7dab94d965893199e7ee01649e2d66f0787a4c558b3118c09e80d4df8269"
+ )
+
+ insert(:address)
+
+ expect(
+ EthereumJSONRPC.Mox,
+ :json_rpc,
+ fn _json, [] ->
+ {:ok}
+ end
+ )
+
+ params = %{
+ "module" => "transaction",
+ "action" => "gettxinfo",
+ "txhash" => "#{transaction.hash}"
+ }
+
+ assert response =
+ conn
+ |> get("/api", params)
+ |> json_response(200)
+
+ assert response["result"]["revertReason"] == ""
+ assert response["status"] == "1"
+ assert response["message"] == "OK"
end
defp resolve_schema(result \\ %{}) do
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/verified_smart_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/verified_smart_contract_controller_test.exs
index d799304324..dd22a12559 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/verified_smart_contract_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/verified_smart_contract_controller_test.exs
@@ -12,6 +12,7 @@ defmodule BlockScoutWeb.API.V1.VerifiedControllerTest do
contract_code_info = Factory.contract_code_info()
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input)
params = %{
"address_hash" => to_string(contract_address.hash),
@@ -40,10 +41,12 @@ defmodule BlockScoutWeb.API.V1.VerifiedControllerTest do
"name" => name,
"optimize" => optimize,
"contract" => contract_source_code,
+ "tx_input" => tx_input,
"expected_bytecode" => expected_bytecode
} = contract_data
contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input)
params = %{
"address_hash" => to_string(contract_address.hash),
diff --git a/apps/block_scout_web/test/support/fixture/smart_contract/contract_with_lib.json b/apps/block_scout_web/test/support/fixture/smart_contract/contract_with_lib.json
index aba02b0ec4..59beb157b6 100644
--- a/apps/block_scout_web/test/support/fixture/smart_contract/contract_with_lib.json
+++ b/apps/block_scout_web/test/support/fixture/smart_contract/contract_with_lib.json
@@ -3,6 +3,7 @@
"compiler_version": "v0.5.11+commit.c082d0b4",
"contract": "pragma solidity 0.5.11;library BadSafeMath { function add(uint256 a, uint256 b) public pure returns (uint256) { uint256 c = a + 2 * b; require(c >= a, \"SafeMath: addition overflow\"); return c; }}contract SimpleStorage { uint256 storedData = 10; using BadSafeMath for uint256; function increment(uint256 x) public { storedData = storedData.add(x); } function set(uint256 x) public { storedData = x; } function get() public view returns (uint256) { return storedData; }}",
"expected_bytecode": "608060405234801561001057600080fd5b50600436106100415760003560e01c806360fe47b1146100465780636d4ce63c146100655780637cf5dab01461007f575b600080fd5b6100636004803603602081101561005c57600080fd5b503561009c565b005b61006d6100a1565b60408051918252519081900360200190f35b6100636004803603602081101561009557600080fd5b50356100a7565b600055565b60005490565b600054733662e222908fa35f013bee37695d0510098b6d7363771602f79091836040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561010257600080fd5b505af4158015610116573d6000803e3d6000fd5b505050506040513d602081101561012c57600080fd5b50516000555056fea265627a7a723158203e59bfb9a5a2e55d38231922c86d8b2ec9b66cb2f6595613674bc4e15290b60764736f6c634300050b0032",
+ "tx_input": "6080604052600a60005534801561001557600080fd5b50610169806100256000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806360fe47b1146100465780636d4ce63c146100655780637cf5dab01461007f575b600080fd5b6100636004803603602081101561005c57600080fd5b503561009c565b005b61006d6100a1565b60408051918252519081900360200190f35b6100636004803603602081101561009557600080fd5b50356100a7565b600055565b60005490565b600054733662e222908fa35f013bee37695d0510098b6d7363771602f79091836040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561010257600080fd5b505af4158015610116573d6000803e3d6000fd5b505050506040513d602081101561012c57600080fd5b50516000555056fea265627a7a723158207809bc828bbcd3de3e6b6483facb0c5902901fc8827283c749c8ea0702eb871f64736f6c634300050b0032",
"external_libraries": {
"BadSafeMath": "0x3662e222908fa35f013bee37695d0510098b6d73"
},
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
index dfe5fa4ea5..a772f615c5 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc.ex
@@ -215,7 +215,18 @@ defmodule EthereumJSONRPC do
@spec fetch_beneficiaries([block_number], json_rpc_named_arguments) ::
{:ok, FetchedBeneficiaries.t()} | {:error, reason :: term} | :ignore
def fetch_beneficiaries(block_numbers, json_rpc_named_arguments) when is_list(block_numbers) do
- Keyword.fetch!(json_rpc_named_arguments, :variant).fetch_beneficiaries(block_numbers, json_rpc_named_arguments)
+ min_block = first_block_to_fetch()
+
+ filtered_block_numbers =
+ block_numbers
+ |> Enum.filter(fn block_number ->
+ block_number >= min_block
+ end)
+
+ Keyword.fetch!(json_rpc_named_arguments, :variant).fetch_beneficiaries(
+ filtered_block_numbers,
+ json_rpc_named_arguments
+ )
end
@doc """
@@ -294,9 +305,17 @@ defmodule EthereumJSONRPC do
@doc """
Fetches internal transactions for entire blocks from variant API.
"""
- def fetch_block_internal_transactions(params_list, json_rpc_named_arguments) when is_list(params_list) do
+ def fetch_block_internal_transactions(block_numbers, json_rpc_named_arguments) when is_list(block_numbers) do
+ min_block = first_block_to_fetch()
+
+ filtered_block_numbers =
+ block_numbers
+ |> Enum.filter(fn block_number ->
+ block_number >= min_block
+ end)
+
Keyword.fetch!(json_rpc_named_arguments, :variant).fetch_block_internal_transactions(
- params_list,
+ filtered_block_numbers,
json_rpc_named_arguments
)
end
@@ -464,4 +483,13 @@ defmodule EthereumJSONRPC do
{:ok, Blocks.from_responses(responses, id_to_params)}
end
end
+
+ defp first_block_to_fetch do
+ string_value = Application.get_env(:indexer, :first_block)
+
+ case Integer.parse(string_value) do
+ {integer, ""} -> integer
+ _ -> 0
+ end
+ end
end
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex
index de83b3601e..ce44f792a7 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/block.ex
@@ -235,6 +235,49 @@ defmodule EthereumJSONRPC.Block do
}
end
+ # Geth: a response from eth_getblockbyhash for uncle blocks is without `totalDifficulty` param
+ def elixir_to_params(
+ %{
+ "difficulty" => difficulty,
+ "extraData" => extra_data,
+ "gasLimit" => gas_limit,
+ "gasUsed" => gas_used,
+ "hash" => hash,
+ "logsBloom" => logs_bloom,
+ "miner" => miner_hash,
+ "number" => number,
+ "parentHash" => parent_hash,
+ "receiptsRoot" => receipts_root,
+ "sha3Uncles" => sha3_uncles,
+ "size" => size,
+ "stateRoot" => state_root,
+ "timestamp" => timestamp,
+ "transactionsRoot" => transactions_root,
+ "uncles" => uncles
+ } = elixir
+ ) do
+ %{
+ difficulty: difficulty,
+ extra_data: extra_data,
+ gas_limit: gas_limit,
+ gas_used: gas_used,
+ hash: hash,
+ logs_bloom: logs_bloom,
+ miner_hash: miner_hash,
+ mix_hash: Map.get(elixir, "mixHash", "0x0"),
+ nonce: Map.get(elixir, "nonce", 0),
+ number: number,
+ parent_hash: parent_hash,
+ receipts_root: receipts_root,
+ sha3_uncles: sha3_uncles,
+ size: size,
+ state_root: state_root,
+ timestamp: timestamp,
+ transactions_root: transactions_root,
+ uncles: uncles
+ }
+ end
+
@doc """
Get `t:EthereumJSONRPC.Transactions.elixir/0` from `t:elixir/0`
@@ -437,7 +480,7 @@ defmodule EthereumJSONRPC.Block do
end
defp entry_to_elixir({key, quantity})
- when key in ~w(difficulty gasLimit gasUsed minimumGasPrice number size totalDifficulty paidFees) and
+ when key in ~w(difficulty gasLimit gasUsed minimumGasPrice number size cumulativeDifficulty totalDifficulty paidFees) and
not is_nil(quantity) do
{key, quantity_to_integer(quantity)}
end
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
index de0f4d1ca3..8cefe10850 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
@@ -58,16 +58,6 @@ defmodule EthereumJSONRPC.Encoder do
end)
end
- def decode_result(result, %{returns: r} = fs) when r in [:string, [:string]] do
- case decode_result(result, %{fs | returns: {:tuple, [:string]}}) do
- {id, {:ok, [{string}]}} ->
- {id, {:ok, [string]}}
-
- error ->
- error
- end
- end
-
def decode_result(%{id: id, result: result}, function_selector) do
types_list = List.wrap(function_selector.returns)
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
index 031b150384..54d812c4c4 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
@@ -9,7 +9,7 @@ defmodule EthereumJSONRPC.Transaction do
"""
require Logger
- import EthereumJSONRPC, only: [quantity_to_integer: 1]
+ import EthereumJSONRPC, only: [quantity_to_integer: 1, integer_to_quantity: 1, request: 1]
alias EthereumJSONRPC
@@ -313,6 +313,20 @@ defmodule EthereumJSONRPC.Transaction do
nil
end
+ def eth_call_request(id, block_number, data, to, from, gas, gas_price, value) do
+ block =
+ case block_number do
+ nil -> "latest"
+ block_number -> integer_to_quantity(block_number)
+ end
+
+ request(%{
+ id: id,
+ method: "eth_call",
+ params: [%{to: to, from: from, data: data, gas: gas, gas_price: gas_price, value: value}, block]
+ })
+ end
+
# double check that no new keys are being missed by requiring explicit match for passthrough
# `t:EthereumJSONRPC.address/0` and `t:EthereumJSONRPC.hash/0` pass through as `Explorer.Chain` can verify correct
# hash format
diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs
index 064b50938f..3118c15882 100644
--- a/apps/ethereum_jsonrpc/mix.exs
+++ b/apps/ethereum_jsonrpc/mix.exs
@@ -70,7 +70,7 @@ defmodule EthereumJsonrpc.MixProject do
# Code coverage
{:excoveralls, "~> 0.10.0", only: [:test], github: "KronicDeth/excoveralls", branch: "circle-workflows"},
# JSONRPC HTTP Post calls
- {:httpoison, "~> 1.0"},
+ {:httpoison, "~> 1.6"},
# Decode/Encode JSON for JSONRPC
{:jason, "~> 1.0"},
# Log errors and application output to separate files
@@ -84,7 +84,7 @@ defmodule EthereumJsonrpc.MixProject do
# Convert unix timestamps in JSONRPC to DateTimes
{:timex, "~> 3.6"},
# Encode/decode function names and arguments
- {:ex_abi, [git: "https://github.com/poanetwork/ex_abi.git", branch: "master"]},
+ {:ex_abi, "~> 0.4"},
# `:verify_fun` for `Socket.Web.connect`
{:ssl_verify_fun, "~> 1.1"},
# `EthereumJSONRPC.WebSocket`
diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex
index 371fdd2beb..bd520b4e70 100644
--- a/apps/explorer/lib/explorer/chain.ex
+++ b/apps/explorer/lib/explorer/chain.ex
@@ -28,11 +28,16 @@ defmodule Explorer.Chain do
alias Ecto.Adapters.SQL
alias Ecto.{Changeset, Multi}
+ alias EthereumJSONRPC.Transaction, as: EthereumJSONRPCTransaction
+
+ alias Explorer.Counters.LastFetchedCounter
+
alias Explorer.Chain
alias Explorer.Chain.{
Address,
Address.CoinBalance,
+ Address.CoinBalanceDaily,
Address.CurrentTokenBalance,
Address.TokenBalance,
Block,
@@ -1517,7 +1522,8 @@ defmodule Explorer.Chain do
from(
a0 in Address,
select: fragment("SUM(a0.fetched_coin_balance)"),
- where: a0.hash != ^burn_address_hash
+ where: a0.hash != ^burn_address_hash,
+ where: a0.fetched_coin_balance > ^0
)
Repo.one!(query) || 0
@@ -1528,7 +1534,8 @@ defmodule Explorer.Chain do
query =
from(
a0 in Address,
- select: fragment("SUM(a0.fetched_coin_balance)")
+ select: fragment("SUM(a0.fetched_coin_balance)"),
+ where: a0.fetched_coin_balance > ^0
)
Repo.one!(query) || 0
@@ -2160,6 +2167,27 @@ defmodule Explorer.Chain do
end
end
+ @spec upsert_last_fetched_counter(map()) :: {:ok, LastFetchedCounter.t()} | {:error, Ecto.Changeset.t()}
+ def upsert_last_fetched_counter(params) do
+ changeset = LastFetchedCounter.changeset(%LastFetchedCounter{}, params)
+
+ Repo.insert(changeset,
+ on_conflict: :replace_all,
+ conflict_target: [:counter_type]
+ )
+ end
+
+ def get_last_fetched_counter(type) do
+ query =
+ from(
+ last_fetched_counter in LastFetchedCounter,
+ where: last_fetched_counter.counter_type == ^type,
+ select: last_fetched_counter.value
+ )
+
+ Repo.one!(query) || 0
+ end
+
defp block_status({number, timestamp}) do
now = DateTime.utc_now()
last_block_period = DateTime.diff(now, timestamp, :millisecond)
@@ -2689,6 +2717,68 @@ defmodule Explorer.Chain do
def transaction_to_status(%Transaction{status: :error, error: error}) when is_binary(error), do: {:error, error}
+ def transaction_to_revert_reason(transaction) do
+ %Transaction{revert_reason: revert_reason} = transaction
+
+ if revert_reason == nil do
+ fetch_tx_revert_reason(transaction)
+ else
+ revert_reason
+ end
+ end
+
+ def fetch_tx_revert_reason(
+ %Transaction{
+ block_number: block_number,
+ to_address_hash: to_address_hash,
+ from_address_hash: from_address_hash,
+ input: data,
+ gas: gas,
+ gas_price: gas_price,
+ value: value
+ } = transaction
+ ) do
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ req =
+ EthereumJSONRPCTransaction.eth_call_request(
+ 0,
+ block_number,
+ data,
+ to_address_hash,
+ from_address_hash,
+ Decimal.to_integer(gas),
+ Wei.hex_format(gas_price),
+ Wei.hex_format(value)
+ )
+
+ data =
+ case EthereumJSONRPC.json_rpc(req, json_rpc_named_arguments) do
+ {:error, %{data: data}} ->
+ data
+
+ _ ->
+ ""
+ end
+
+ revert_reason_parts = String.split(data, "revert: ")
+
+ formatted_revert_reason =
+ if Enum.count(revert_reason_parts) > 1 do
+ Enum.at(revert_reason_parts, 1)
+ else
+ data
+ end
+
+ if byte_size(formatted_revert_reason) > 0 do
+ transaction
+ |> Changeset.change(%{revert_reason: formatted_revert_reason})
+ |> Repo.update()
+ end
+
+ formatted_revert_reason
+ end
+
@doc """
The `t:Explorer.Chain.Transaction.t/0` or `t:Explorer.Chain.InternalTransaction.t/0` `value` of the `transaction` in
`unit`.
@@ -2716,6 +2806,42 @@ defmodule Explorer.Chain do
|> Data.to_string()
end
+ def smart_contract_creation_tx_bytecode(address_hash) do
+ creation_tx_query =
+ from(
+ tx in Transaction,
+ where: tx.created_contract_address_hash == ^address_hash,
+ select: tx.input
+ )
+
+ tx_input =
+ creation_tx_query
+ |> Repo.one()
+
+ if tx_input do
+ Data.to_string(tx_input)
+ else
+ creation_int_tx_query =
+ from(
+ itx in InternalTransaction,
+ join: t in assoc(itx, :transaction),
+ where: itx.created_contract_address_hash == ^address_hash,
+ where: t.status == ^1,
+ select: itx.init
+ )
+
+ itx_init_code =
+ creation_int_tx_query
+ |> Repo.one()
+
+ if itx_init_code do
+ Data.to_string(itx_init_code)
+ else
+ nil
+ end
+ end
+ end
+
@doc """
Checks if an address is a contract
"""
@@ -2777,6 +2903,9 @@ defmodule Explorer.Chain do
transaction.contracts_creation_internal_transaction && transaction.contracts_creation_internal_transaction.input ->
Data.to_string(transaction.contracts_creation_internal_transaction.input)
+ transaction.contracts_creation_internal_transaction && transaction.contracts_creation_internal_transaction.init ->
+ Data.to_string(transaction.contracts_creation_internal_transaction.init)
+
transaction.contracts_creation_transaction && transaction.contracts_creation_transaction.input ->
Data.to_string(transaction.contracts_creation_transaction.input)
@@ -3428,17 +3557,69 @@ defmodule Explorer.Chain do
def address_to_coin_balances(address_hash, options) do
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
- address_hash
- |> CoinBalance.fetch_coin_balances(paging_options)
- |> page_coin_balances(paging_options)
- |> Repo.all()
- |> Enum.dedup_by(fn record ->
- if record.delta == Decimal.new(0) do
- :dup
- else
- System.unique_integer()
- end
- end)
+ balances_raw =
+ address_hash
+ |> CoinBalance.fetch_coin_balances(paging_options)
+ |> page_coin_balances(paging_options)
+ |> Repo.all()
+
+ if Enum.empty?(balances_raw) do
+ balances_raw
+ else
+ balances_raw_filtered =
+ balances_raw
+ |> Enum.filter(fn balance -> balance.value end)
+
+ min_block_number =
+ balances_raw_filtered
+ |> Enum.min_by(fn balance -> balance.block_number end, fn -> %{} end)
+ |> Map.get(:block_number)
+
+ max_block_number =
+ balances_raw_filtered
+ |> Enum.max_by(fn balance -> balance.block_number end, fn -> %{} end)
+ |> Map.get(:block_number)
+
+ min_block_timestamp = find_block_timestamp(min_block_number)
+ max_block_timestamp = find_block_timestamp(max_block_number)
+
+ min_block_unix_timestamp =
+ min_block_timestamp
+ |> Timex.to_unix()
+
+ max_block_unix_timestamp =
+ max_block_timestamp
+ |> Timex.to_unix()
+
+ blocks_delta = max_block_number - min_block_number
+
+ balances_with_dates =
+ if blocks_delta > 0 do
+ balances_raw_filtered
+ |> Enum.map(fn balance ->
+ date =
+ trunc(
+ min_block_unix_timestamp +
+ (balance.block_number - min_block_number) * (max_block_unix_timestamp - min_block_unix_timestamp) /
+ blocks_delta
+ )
+
+ formatted_date = Timex.from_unix(date)
+ %{balance | block_timestamp: formatted_date}
+ end)
+ else
+ balances_raw_filtered
+ |> Enum.map(fn balance ->
+ date = min_block_unix_timestamp
+
+ formatted_date = Timex.from_unix(date)
+ %{balance | block_timestamp: formatted_date}
+ end)
+ end
+
+ balances_with_dates
+ |> Enum.sort(fn balance1, balance2 -> balance1.block_number >= balance2.block_number end)
+ end
end
def get_coin_balance(address_hash, block_number) do
@@ -3455,8 +3636,9 @@ defmodule Explorer.Chain do
|> Repo.one()
address_hash
- |> CoinBalance.balances_by_day(latest_block_timestamp)
+ |> CoinBalanceDaily.balances_by_day()
|> Repo.all()
+ |> Enum.sort_by(fn %{date: d} -> {d.year, d.month, d.day} end)
|> replace_last_value(latest_block_timestamp)
|> normalize_balances_by_day()
end
@@ -3471,7 +3653,6 @@ defmodule Explorer.Chain do
defp normalize_balances_by_day(balances_by_day) do
result =
balances_by_day
- |> Enum.map(fn day -> Map.take(day, [:date, :value]) end)
|> Enum.filter(fn day -> day.value end)
|> Enum.map(fn day -> Map.update!(day, :date, &to_string(&1)) end)
|> Enum.map(fn day -> Map.update!(day, :value, &Wei.to(&1, :ether)) end)
@@ -4269,4 +4450,11 @@ defmodule Explorer.Chain do
block_index
end
end
+
+ defp find_block_timestamp(number) do
+ Block
+ |> where([b], b.number == ^number)
+ |> select([b], b.timestamp)
+ |> Repo.one()
+ end
end
diff --git a/apps/explorer/lib/explorer/chain/address/coin_balance.ex b/apps/explorer/lib/explorer/chain/address/coin_balance.ex
index f3647a8f54..cada366173 100644
--- a/apps/explorer/lib/explorer/chain/address/coin_balance.ex
+++ b/apps/explorer/lib/explorer/chain/address/coin_balance.ex
@@ -72,16 +72,18 @@ defmodule Explorer.Chain.Address.CoinBalance do
The last coin balance from an Address is the last block indexed.
"""
def fetch_coin_balances(address_hash, %PagingOptions{page_size: page_size}) do
- from(
- cb in CoinBalance,
- where: cb.address_hash == ^address_hash,
- where: not is_nil(cb.value),
- inner_join: b in Block,
- on: cb.block_number == b.number,
- order_by: [desc: :block_number],
- limit: ^page_size,
- select_merge: %{delta: fragment("value - coalesce(lag(value, 1) over (order by block_number), 0)")},
- select_merge: %{block_timestamp: b.timestamp}
+ query =
+ from(
+ cb in CoinBalance,
+ where: cb.address_hash == ^address_hash,
+ where: not is_nil(cb.value),
+ order_by: [desc: :block_number],
+ select_merge: %{delta: fragment("value - coalesce(lead(value, 1) over (order by block_number desc), 0)")}
+ )
+
+ from(balance in subquery(query),
+ where: balance.delta != 0,
+ limit: ^page_size
)
end
@@ -90,29 +92,55 @@ defmodule Explorer.Chain.Address.CoinBalance do
corresponds to the maximum balance in that day. Only the last 90 days of data are used.
"""
def balances_by_day(address_hash, block_timestamp \\ nil) do
+ {days_to_consider, _} =
+ Application.get_env(:block_scout_web, BlockScoutWeb.Chain.Address.CoinBalance)[:coin_balance_history_days]
+ |> Integer.parse()
+
CoinBalance
|> join(:inner, [cb], b in Block, on: cb.block_number == b.number)
|> where([cb], cb.address_hash == ^address_hash)
- |> limit_time_interval(block_timestamp)
+ |> limit_time_interval(days_to_consider, block_timestamp)
|> group_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp))
|> order_by([cb, b], fragment("date_trunc('day', ?)", b.timestamp))
|> select([cb, b], %{date: type(fragment("date_trunc('day', ?)", b.timestamp), :date), value: max(cb.value)})
end
- def limit_time_interval(query, nil) do
- query |> where([cb, b], b.timestamp >= fragment("date_trunc('day', now()) - interval '90 days'"))
+ def limit_time_interval(query, days_to_consider, nil) do
+ query
+ |> where(
+ [cb, b],
+ b.timestamp >=
+ fragment("date_trunc('day', now() - CAST(? AS INTERVAL))", ^%Postgrex.Interval{days: days_to_consider})
+ )
end
- def limit_time_interval(query, %{timestamp: timestamp}) do
- query |> where([cb, b], b.timestamp >= fragment("(? AT TIME ZONE ?) - interval '90 days'", ^timestamp, ^"Etc/UTC"))
+ def limit_time_interval(query, days_to_consider, %{timestamp: timestamp}) do
+ query
+ |> where(
+ [cb, b],
+ b.timestamp >=
+ fragment(
+ "(? AT TIME ZONE ?) - CAST(? AS INTERVAL)",
+ ^timestamp,
+ ^"Etc/UTC",
+ ^%Postgrex.Interval{days: days_to_consider}
+ )
+ )
end
def last_coin_balance_timestamp(address_hash) do
- CoinBalance
- |> join(:inner, [cb], b in Block, on: cb.block_number == b.number)
- |> where([cb], cb.address_hash == ^address_hash)
- |> last(:block_number)
- |> select([cb, b], %{timestamp: b.timestamp, value: cb.value})
+ coin_balance_query =
+ CoinBalance
+ |> where([cb], cb.address_hash == ^address_hash)
+ |> last(:block_number)
+ |> select([cb, b], %{block_number: cb.block_number, value: cb.value})
+
+ from(
+ cb in subquery(coin_balance_query),
+ inner_join: b in Block,
+ on: cb.block_number == b.number,
+ select: %{timestamp: b.timestamp, value: cb.value}
+ )
end
def changeset(%__MODULE__{} = balance, params) do
diff --git a/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex b/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex
new file mode 100644
index 0000000000..ca90840771
--- /dev/null
+++ b/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex
@@ -0,0 +1,74 @@
+defmodule Explorer.Chain.Address.CoinBalanceDaily do
+ @moduledoc """
+ Maximum `t:Explorer.Chain.Wei.t/0` `value` of `t:Explorer.Chain.Address.t/0` at the day.
+ This table is used to display coinn balance history chart.
+ """
+
+ use Explorer.Schema
+
+ alias Explorer.Chain.{Address, Hash, Wei}
+ alias Explorer.Chain.Address.CoinBalanceDaily
+
+ @optional_fields ~w(value)a
+ @required_fields ~w(address_hash day)a
+ @allowed_fields @optional_fields ++ @required_fields
+
+ @typedoc """
+ * `address` - the `t:Explorer.Chain.Address.t/0`.
+ * `address_hash` - foreign key for `address`.
+ * `day` - the `t:Date.t/0`.
+ * `inserted_at` - When the balance was first inserted into the database.
+ * `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)
+ field(:value, Wei)
+
+ timestamps()
+
+ belongs_to(:address, Address, foreign_key: :address_hash, references: :hash, type: Hash.Address)
+ end
+
+ @doc """
+ Builds an `Ecto.Query` to fetch a series of balances by day for the given account. Each element in the series
+ corresponds to the maximum balance in that day. Only the last `n` days of data are used.
+ `n` is configurable via COIN_BALANCE_HISTORY_DAYS ENV var.
+ """
+ def balances_by_day(address_hash) do
+ {days_to_consider, _} =
+ Application.get_env(:block_scout_web, BlockScoutWeb.Chain.Address.CoinBalance)[:coin_balance_history_days]
+ |> Integer.parse()
+
+ CoinBalanceDaily
+ |> where([cbd], cbd.address_hash == ^address_hash)
+ |> limit_time_interval(days_to_consider)
+ |> select([cbd], %{date: cbd.day, value: cbd.value})
+ end
+
+ def limit_time_interval(query, days_to_consider) do
+ query
+ |> where(
+ [cbd],
+ cbd.day >= fragment("date_trunc('day', now() - CAST(? AS INTERVAL))", ^%Postgrex.Interval{days: days_to_consider})
+ )
+ end
+
+ def changeset(%__MODULE__{} = balance, params) do
+ balance
+ |> cast(params, @allowed_fields)
+ |> validate_required(@required_fields)
+ |> foreign_key_constraint(:address_hash)
+ |> unique_constraint(:day, name: :address_coin_balances_daily_address_hash_day_index)
+ end
+end
diff --git a/apps/explorer/lib/explorer/chain/cache/address_sum_minus_burnt.ex b/apps/explorer/lib/explorer/chain/cache/address_sum_minus_burnt.ex
index f8eb22a405..635b19241e 100644
--- a/apps/explorer/lib/explorer/chain/cache/address_sum_minus_burnt.ex
+++ b/apps/explorer/lib/explorer/chain/cache/address_sum_minus_burnt.ex
@@ -31,6 +31,13 @@ defmodule Explorer.Chain.Cache.AddressSumMinusBurnt do
try do
result = Chain.fetch_sum_coin_total_supply_minus_burnt()
+ params = %{
+ counter_type: "sum_coin_total_supply_minus_burnt",
+ value: result
+ }
+
+ Chain.upsert_last_fetched_counter(params)
+
set_sum_minus_burnt(result)
rescue
e ->
diff --git a/apps/explorer/lib/explorer/chain/cache/pending_transactions.ex b/apps/explorer/lib/explorer/chain/cache/pending_transactions.ex
deleted file mode 100644
index 686b5e7372..0000000000
--- a/apps/explorer/lib/explorer/chain/cache/pending_transactions.ex
+++ /dev/null
@@ -1,42 +0,0 @@
-defmodule Explorer.Chain.Cache.PendingTransactions do
- @moduledoc """
- Caches the latest pending transactions
- """
-
- alias Explorer.Chain.Transaction
-
- use Explorer.Chain.OrderedCache,
- name: :pending_transactions,
- max_size: 51,
- preloads: [
- :block,
- created_contract_address: :names,
- from_address: :names,
- to_address: :names,
- token_transfers: :token,
- token_transfers: :from_address,
- token_transfers: :to_address
- ],
- ttl_check_interval: Application.get_env(:explorer, __MODULE__)[:ttl_check_interval],
- global_ttl: Application.get_env(:explorer, __MODULE__)[:global_ttl]
-
- @type element :: Transaction.t()
-
- @type id :: {non_neg_integer(), non_neg_integer()}
-
- def element_to_id(%Transaction{inserted_at: inserted_at, hash: hash}) do
- {inserted_at, hash}
- end
-
- def update_pending(transactions) when is_nil(transactions), do: :ok
-
- def update_pending(transactions) do
- transactions
- |> Enum.filter(&pending?(&1))
- |> update()
- end
-
- defp pending?(transaction) do
- is_nil(transaction.block_hash) and (is_nil(transaction.error) or transaction.error != "dropped/replaced")
- end
-end
diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances_daily.ex b/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances_daily.ex
new file mode 100644
index 0000000000..d8f279d9ad
--- /dev/null
+++ b/apps/explorer/lib/explorer/chain/import/runner/address/coin_balances_daily.ex
@@ -0,0 +1,139 @@
+defmodule Explorer.Chain.Import.Runner.Address.CoinBalancesDaily do
+ @moduledoc """
+ Bulk imports `t:Explorer.Chain.Address.CoinBalancesDaily.t/0`.
+ """
+
+ require Ecto.Query
+
+ import Ecto.Query, only: [from: 2]
+
+ alias Ecto.{Changeset, Multi, Repo}
+ alias Explorer.Chain.Address.CoinBalanceDaily
+ alias Explorer.Chain.{Hash, Import, Wei}
+
+ @behaviour Import.Runner
+
+ # milliseconds
+ @timeout 60_000
+
+ @type imported :: [
+ %{required(:address_hash) => Hash.Address.t(), required(:day) => Date.t()}
+ ]
+
+ @impl Import.Runner
+ def ecto_schema_module, do: CoinBalanceDaily
+
+ @impl Import.Runner
+ def option_key, do: :address_coin_balances_daily
+
+ @impl Import.Runner
+ def imported_table_row do
+ %{
+ value_type: "[%{address_hash: Explorer.Chain.Hash.t(), day: Date.t()}]",
+ value_description: "List of maps of the `t:#{ecto_schema_module()}.t/0` `address_hash` and `day`"
+ }
+ end
+
+ @impl Import.Runner
+ def run(multi, changes_list, %{timestamps: timestamps} = options) do
+ insert_options =
+ options
+ |> Map.get(option_key(), %{})
+ |> Map.take(~w(on_conflict timeout)a)
+ |> Map.put_new(:timeout, @timeout)
+ |> Map.put(:timestamps, timestamps)
+
+ Multi.run(multi, :address_coin_balances_daily, fn repo, _ ->
+ insert(repo, changes_list, insert_options)
+ end)
+ end
+
+ @impl Import.Runner
+ def timeout, do: @timeout
+
+ @spec insert(
+ Repo.t(),
+ [
+ %{
+ required(:address_hash) => Hash.Address.t(),
+ required(:day) => Date.t(),
+ required(:value) => Wei.t()
+ }
+ ],
+ %{
+ optional(:on_conflict) => Import.Runner.on_conflict(),
+ required(:timeout) => timeout,
+ required(:timestamps) => Import.timestamps()
+ }
+ ) ::
+ {:ok, [%{required(:address_hash) => Hash.Address.t(), required(:day) => Date.t()}]}
+ | {:error, [Changeset.t()]}
+ defp insert(repo, changes_list, %{timeout: timeout, timestamps: timestamps} = options) when is_list(changes_list) do
+ on_conflict = Map.get_lazy(options, :on_conflict, &default_on_conflict/0)
+
+ combined_changes_list =
+ changes_list
+ |> Enum.reduce([], fn change, acc ->
+ if Enum.empty?(acc) do
+ [change | acc]
+ else
+ target_item =
+ Enum.find(acc, fn item ->
+ item.day == change.day && item.address_hash == change.address_hash
+ end)
+
+ if target_item do
+ if change.value > target_item.value do
+ acc_updated = List.delete(acc, target_item)
+ [change | acc_updated]
+ else
+ acc
+ end
+ else
+ [change | acc]
+ end
+ end
+ end)
+
+ # Enforce CoinBalanceDaily ShareLocks order (see docs: sharelocks.md)
+ ordered_changes_list = Enum.sort_by(combined_changes_list, &{&1.address_hash, &1.day})
+
+ {:ok, _} =
+ Import.insert_changes_list(
+ repo,
+ ordered_changes_list,
+ conflict_target: [:address_hash, :day],
+ on_conflict: on_conflict,
+ for: CoinBalanceDaily,
+ timeout: timeout,
+ timestamps: timestamps
+ )
+
+ {:ok, Enum.map(ordered_changes_list, &Map.take(&1, ~w(address_hash day)a))}
+ end
+
+ def default_on_conflict do
+ from(
+ balance in CoinBalanceDaily,
+ update: [
+ set: [
+ value:
+ fragment(
+ """
+ CASE WHEN EXCLUDED.value IS NOT NULL AND EXCLUDED.value > ? THEN
+ EXCLUDED.value
+ ELSE
+ ?
+ END
+ """,
+ balance.value,
+ balance.value
+ ),
+ inserted_at: fragment("LEAST(EXCLUDED.inserted_at, ?)", balance.inserted_at),
+ updated_at: fragment("GREATEST(EXCLUDED.updated_at, ?)", balance.updated_at)
+ ]
+ ],
+ where: fragment("EXCLUDED.value IS NOT NULL")
+ )
+ end
+end
diff --git a/apps/explorer/lib/explorer/chain/import/stage/address_referencing.ex b/apps/explorer/lib/explorer/chain/import/stage/address_referencing.ex
index 2575a0eab8..a428d51b0c 100644
--- a/apps/explorer/lib/explorer/chain/import/stage/address_referencing.ex
+++ b/apps/explorer/lib/explorer/chain/import/stage/address_referencing.ex
@@ -14,7 +14,8 @@ defmodule Explorer.Chain.Import.Stage.AddressReferencing do
Runner.Address.CoinBalances,
Runner.Blocks,
Runner.StakingPools,
- Runner.StakingPoolsDelegators
+ Runner.StakingPoolsDelegators,
+ Runner.Address.CoinBalancesDaily
]
@impl Stage
diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex
index 0db7d7e613..9d4c03134a 100644
--- a/apps/explorer/lib/explorer/chain/smart_contract.ex
+++ b/apps/explorer/lib/explorer/chain/smart_contract.ex
@@ -326,6 +326,7 @@ defmodule Explorer.Chain.SmartContract do
defp upsert_contract_methods(changeset), do: changeset
defp error_message(:compilation), do: "There was an error compiling your contract."
+ defp error_message(:compiler_version), do: "Compiler version does not match, please try again."
defp error_message(:generated_bytecode), do: "Bytecode does not match, please try again."
defp error_message(:constructor_arguments), do: "Constructor arguments do not match, please try again."
defp error_message(:name), do: "Wrong contract name, please try again."
diff --git a/apps/explorer/lib/explorer/chain/token_transfer.ex b/apps/explorer/lib/explorer/chain/token_transfer.ex
index 228d0ce660..344e8187e8 100644
--- a/apps/explorer/lib/explorer/chain/token_transfer.ex
+++ b/apps/explorer/lib/explorer/chain/token_transfer.ex
@@ -281,6 +281,7 @@ defmodule Explorer.Chain.TokenTransfer do
end
@doc """
+ Innventory tab query.
A token ERC-721 is considered unique because it corresponds to the possession
of a specific asset.
@@ -293,9 +294,9 @@ defmodule Explorer.Chain.TokenTransfer do
tt in TokenTransfer,
left_join: instance in Instance,
on: tt.token_contract_address_hash == instance.token_contract_address_hash and tt.token_id == instance.token_id,
- where: tt.token_contract_address_hash == ^contract_address_hash,
+ where: instance.token_contract_address_hash == ^contract_address_hash,
order_by: [desc: tt.block_number],
- distinct: tt.token_id,
+ distinct: [desc: tt.token_id],
preload: [:to_address],
select: %{tt | instance: instance}
)
diff --git a/apps/explorer/lib/explorer/chain/transaction.ex b/apps/explorer/lib/explorer/chain/transaction.ex
index 66127868c6..9d60d58edd 100644
--- a/apps/explorer/lib/explorer/chain/transaction.ex
+++ b/apps/explorer/lib/explorer/chain/transaction.ex
@@ -30,7 +30,7 @@ defmodule Explorer.Chain.Transaction do
@optional_attrs ~w(block_hash block_number created_contract_address_hash cumulative_gas_used earliest_processing_start
error gas_used index created_contract_code_indexed_at status
- to_address_hash)a
+ to_address_hash revert_reason)a
@required_attrs ~w(from_address_hash gas gas_price hash input nonce r s v value)a
@@ -106,6 +106,7 @@ defmodule Explorer.Chain.Transaction do
* `internal_transactions` - transactions (value transfers) created while executing contract used for this
transaction
* `created_contract_code_indexed_at` - when created `address` code was fetched by `Indexer`
+ * `revert_reason` - revert reason of transaction
| `status` | `contract_creation_address_hash` | `input` | Token Transfer? | `internal_transactions_indexed_at` | `internal_transactions` | Description |
|----------|----------------------------------|------------|-----------------|-------------------------------------------|-------------------------|-----------------------------------------------------------------------------------------------------|
@@ -129,6 +130,7 @@ defmodule Explorer.Chain.Transaction do
* `uncles` - uncle blocks where `forks` were collated
* `v` - The V field of the signature.
* `value` - wei transferred from `from_address` to `to_address`
+ * `revert_reason` - revert reason of transaction
"""
@type t :: %__MODULE__{
block: %Ecto.Association.NotLoaded{} | Block.t() | nil,
@@ -159,7 +161,8 @@ defmodule Explorer.Chain.Transaction do
to_address_hash: Hash.Address.t() | nil,
uncles: %Ecto.Association.NotLoaded{} | [Block.t()],
v: v(),
- value: Wei.t()
+ value: Wei.t(),
+ revert_reason: String.t()
}
@derive {Poison.Encoder,
@@ -199,6 +202,7 @@ defmodule Explorer.Chain.Transaction do
field(:status, Status)
field(:v, :decimal)
field(:value, Wei)
+ field(:revert_reason, :string)
# 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
diff --git a/apps/explorer/lib/explorer/chain_spec/parity/importer.ex b/apps/explorer/lib/explorer/chain_spec/parity/importer.ex
index ba4c7a3e37..cdd2da1eed 100644
--- a/apps/explorer/lib/explorer/chain_spec/parity/importer.ex
+++ b/apps/explorer/lib/explorer/chain_spec/parity/importer.ex
@@ -5,6 +5,7 @@ defmodule Explorer.ChainSpec.Parity.Importer do
require Logger
+ alias EthereumJSONRPC.Blocks
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Block.{EmissionReward, Range}
alias Explorer.Chain.Hash.Address, as: AddressHash
@@ -33,6 +34,21 @@ defmodule Explorer.ChainSpec.Parity.Importer do
end)
|> Enum.to_list()
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(1..1, json_rpc_named_arguments)
+
+ day = DateTime.to_date(timestamp)
+
+ balance_daily_params =
+ chain_spec
+ |> genesis_accounts()
+ |> Stream.map(fn balance_map ->
+ Map.put(balance_map, :day, day)
+ end)
+ |> Enum.to_list()
+
address_params =
balance_params
|> Stream.map(fn %{address_hash: hash} = map ->
@@ -40,7 +56,11 @@ defmodule Explorer.ChainSpec.Parity.Importer do
end)
|> Enum.to_list()
- params = %{address_coin_balances: %{params: balance_params}, addresses: %{params: address_params}}
+ params = %{
+ address_coin_balances: %{params: balance_params},
+ address_coin_balances_daily: %{params: balance_daily_params},
+ addresses: %{params: address_params}
+ }
Chain.import(params)
end
diff --git a/apps/explorer/lib/explorer/counters/last_fetched_counter.ex b/apps/explorer/lib/explorer/counters/last_fetched_counter.ex
new file mode 100644
index 0000000000..e4d684c2f1
--- /dev/null
+++ b/apps/explorer/lib/explorer/counters/last_fetched_counter.ex
@@ -0,0 +1,30 @@
+defmodule Explorer.Counters.LastFetchedCounter do
+ @moduledoc """
+ 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)
+ field(:value, :decimal)
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(struct, params \\ %{}) do
+ struct
+ |> cast(params, [:counter_type, :value])
+ |> validate_required([:counter_type])
+ end
+end
diff --git a/apps/explorer/lib/explorer/etherscan.ex b/apps/explorer/lib/explorer/etherscan.ex
index 1caf9f7e64..82fd5a45f9 100644
--- a/apps/explorer/lib/explorer/etherscan.ex
+++ b/apps/explorer/lib/explorer/etherscan.ex
@@ -332,6 +332,7 @@ defmodule Explorer.Etherscan do
status
to_address_hash
value
+ revert_reason
)a
defp list_transactions(address_hash, max_block_number, options) do
diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
index c5c1b01930..3b83cafed6 100644
--- a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
+++ b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex
@@ -59,7 +59,7 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
"type" => "function"
}
],
- "bytecode" => "6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820834bdab406d80509618957aa1a5ad1a4b77f4f1149078675940494ebe5b4147b0029",
+ "bytecode" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820834bdab406d80509618957aa1a5ad1a4b77f4f1149078675940494ebe5b4147b0029",
"name" => "SimpleStorage"
}
}
@@ -92,19 +92,18 @@ defmodule Explorer.SmartContract.Solidity.CodeCompiler do
[
Application.app_dir(:explorer, "priv/compile_solc.js"),
create_source_file(code),
- compiler_version,
+ path,
optimize_value(optimize),
optimization_runs,
@new_contract_name,
external_libs_string,
- checked_evm_version,
- path
+ checked_evm_version
]
)
with {:ok, decoded} <- Jason.decode(response),
{:ok, contracts} <- get_contracts(decoded),
- %{"abi" => abi, "evm" => %{"deployedBytecode" => %{"object" => bytecode}}} <-
+ %{"abi" => abi, "evm" => %{"bytecode" => %{"object" => bytecode}}} <-
get_contract_info(contracts, name) do
{:ok, %{"abi" => abi, "bytecode" => bytecode, "name" => name}}
else
diff --git a/apps/explorer/lib/explorer/smart_contract/verifier.ex b/apps/explorer/lib/explorer/smart_contract/verifier.ex
index 884870a4a1..1b4eb88a3e 100644
--- a/apps/explorer/lib/explorer/smart_contract/verifier.ex
+++ b/apps/explorer/lib/explorer/smart_contract/verifier.ex
@@ -1,3 +1,4 @@
+# credo:disable-for-this-file
defmodule Explorer.SmartContract.Verifier do
@moduledoc """
Module responsible to verify the Smart Contract.
@@ -11,6 +12,13 @@ defmodule Explorer.SmartContract.Verifier do
alias Explorer.SmartContract.Solidity.CodeCompiler
alias Explorer.SmartContract.Verifier.ConstructorArguments
+ @metadata_hash_prefix_0_4_23 "a165627a7a72305820"
+ @metadata_hash_prefix_0_5_10 "a265627a7a72305820"
+ @metadata_hash_prefix_0_5_11 "a265627a7a72315820"
+ @metadata_hash_prefix_0_6_0 "a264697066735822"
+
+ @metadata_hash_common_suffix "64736f6c63"
+
def evaluate_authenticity(_, %{"name" => ""}), do: {:error, :name}
def evaluate_authenticity(_, %{"contract_source_code" => ""}),
@@ -76,16 +84,28 @@ defmodule Explorer.SmartContract.Verifier do
contract_source_code,
contract_name
) do
- generated_bytecode = extract_bytecode(bytecode)
+ %{
+ "metadata_hash" => _generated_metadata_hash,
+ "bytecode" => generated_bytecode,
+ "compiler_version" => generated_compiler_version
+ } = extract_bytecode_and_metadata_hash(bytecode)
- "0x" <> blockchain_bytecode =
+ "0x" <> blockchain_created_tx_input =
address_hash
- |> Chain.smart_contract_bytecode()
+ |> Chain.smart_contract_creation_tx_bytecode()
+
+ %{
+ "metadata_hash" => _metadata_hash,
+ "bytecode" => blockchain_bytecode_without_whisper,
+ "compiler_version" => compiler_version
+ } = extract_bytecode_and_metadata_hash(blockchain_created_tx_input)
- blockchain_bytecode_without_whisper = extract_bytecode(blockchain_bytecode)
empty_constructor_arguments = arguments_data == "" or arguments_data == nil
cond do
+ generated_compiler_version != compiler_version ->
+ {:error, :compiler_version}
+
generated_bytecode != blockchain_bytecode_without_whisper &&
!try_library_verification(generated_bytecode, blockchain_bytecode_without_whisper) ->
{:error, :generated_bytecode}
@@ -136,40 +156,87 @@ defmodule Explorer.SmartContract.Verifier do
For more information on the swarm hash, check out:
https://solidity.readthedocs.io/en/v0.5.3/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode
"""
- def extract_bytecode("0x" <> code) do
- "0x" <> extract_bytecode(code)
+ def extract_bytecode_and_metadata_hash("0x" <> code) do
+ %{"metadata_hash" => metadata_hash, "bytecode" => bytecode, "compiler_version" => compiler_version} =
+ extract_bytecode_and_metadata_hash(code)
+
+ %{"metadata_hash" => metadata_hash, "bytecode" => "0x" <> bytecode, "compiler_version" => compiler_version}
end
- def extract_bytecode(code) do
- do_extract_bytecode([], String.downcase(code))
+ def extract_bytecode_and_metadata_hash(code) do
+ do_extract_bytecode_and_metadata_hash([], String.downcase(code), nil, nil)
end
- defp do_extract_bytecode(extracted, remaining) do
+ defp do_extract_bytecode_and_metadata_hash(extracted, remaining, metadata_hash, compiler_version) do
case remaining do
<<>> ->
- extracted
- |> Enum.reverse()
- |> :binary.list_to_bin()
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
- "a165627a7a72305820" <> <<_::binary-size(64)>> <> "0029" <> _constructor_arguments ->
- extracted
- |> Enum.reverse()
- |> :binary.list_to_bin()
+ @metadata_hash_prefix_0_4_23 <> <> <> "0029" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
# Solidity >= 0.5.9; https://github.com/ethereum/solidity/blob/aa4ee3a1559ebc0354926af962efb3fcc7dc15bd/docs/metadata.rst
- "a265627a7a72305820" <>
- <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments ->
- extracted
- |> Enum.reverse()
- |> :binary.list_to_bin()
+ @metadata_hash_prefix_0_5_10 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "43" <> <> <> "0032" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_10 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7826" <> <> <> "0057" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_10 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7827" <> <> <> "0057" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_10 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7828" <> <> <> "0058" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_10 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7829" <> <> <> "0059" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
# Solidity >= 0.5.11 https://github.com/ethereum/solidity/blob/develop/Changelog.md#0511-2019-08-12
# Metadata: Update the swarm hash to the current specification, changes bzzr0 to bzzr1 and urls to use bzz-raw://
- "a265627a7a72315820" <>
- <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> _constructor_arguments ->
- extracted
- |> Enum.reverse()
- |> :binary.list_to_bin()
+ @metadata_hash_prefix_0_5_11 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "43" <> <> <> "0032" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_11 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7826" <> <> <> "0057" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_11 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7827" <> <> <> "0057" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_11 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7828" <> <> <> "0058" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_5_11 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7829" <> <> <> "0059" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
# Solidity >= 0.6.0 https://github.com/ethereum/solidity/blob/develop/Changelog.md#060-2019-12-17
# https://github.com/ethereum/solidity/blob/26b700771e9cc9c956f0503a05de69a1be427963/docs/metadata.rst#encoding-of-the-metadata-hash-in-the-bytecode
@@ -181,17 +248,50 @@ defmodule Explorer.SmartContract.Verifier do
# 0x00 0x32
# Note: there is a bug in the docs. Instead of 0x32, 0x33 should be used.
# Fixing PR has been created https://github.com/ethereum/solidity/pull/8174
- "a264697066735822" <>
- <<_::binary-size(68)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0033" <> _constructor_arguments ->
- extracted
- |> Enum.reverse()
- |> :binary.list_to_bin()
+ @metadata_hash_prefix_0_6_0 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "43" <> <> <> "0033" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_6_0 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7826" <> <> <> "0057" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_6_0 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7827" <> <> <> "0057" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_6_0 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7828" <> <> <> "0058" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
+
+ @metadata_hash_prefix_0_6_0 <>
+ <> <>
+ @metadata_hash_common_suffix <>
+ "7829" <> <> <> "0059" <> _constructor_arguments ->
+ do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version)
<> <> rest ->
- do_extract_bytecode([next | extracted], rest)
+ do_extract_bytecode_and_metadata_hash([next | extracted], rest, metadata_hash, compiler_version)
end
end
+ defp do_extract_bytecode_and_metadata_hash_output(metadata_hash, extracted, compiler_version) do
+ bytecode =
+ extracted
+ |> Enum.reverse()
+ |> :binary.list_to_bin()
+
+ %{"metadata_hash" => metadata_hash, "bytecode" => bytecode, "compiler_version" => compiler_version}
+ end
+
def previous_evm_versions(current_evm_version) do
index = Enum.find_index(CodeCompiler.allowed_evm_versions(), fn el -> el == current_evm_version end)
diff --git a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex
index f5676784ae..8edc758693 100644
--- a/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex
+++ b/apps/explorer/lib/explorer/smart_contract/verifier/constructor_arguments.ex
@@ -1,3 +1,4 @@
+# credo:disable-for-this-file
defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
@moduledoc """
Smart contract contrstructor arguments verification logic.
@@ -5,6 +6,13 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
alias ABI.{FunctionSelector, TypeDecoder}
alias Explorer.Chain
+ @metadata_hash_prefix_0_4_23 "a165627a7a72305820"
+ @metadata_hash_prefix_0_5_10 "a265627a7a72305820"
+ @metadata_hash_prefix_0_5_11 "a265627a7a72315820"
+ @metadata_hash_prefix_0_6_0 "a264697066735822"
+
+ @metadata_hash_common_suffix "64736f6c63"
+
def verify(address_hash, contract_code, arguments_data, contract_source_code, contract_name) do
arguments_data = arguments_data |> String.trim_trailing() |> String.trim_leading("0x")
@@ -34,19 +42,127 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
defp extract_constructor_arguments(code, check_func, contract_source_code, contract_name) do
case code do
# Solidity ~ 4.23 # https://solidity.readthedocs.io/en/v0.4.23/metadata.html
- "a165627a7a72305820" <> <<_::binary-size(64)>> <> "0029" <> constructor_arguments ->
- extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code, contract_name)
+ @metadata_hash_prefix_0_4_23 <> <<_::binary-size(64)>> <> "0029" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_4_23
+ )
# Solidity >= 0.5.10 https://solidity.readthedocs.io/en/v0.5.10/metadata.html
- "a265627a7a72305820" <>
- <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments ->
- extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code, contract_name)
+ @metadata_hash_prefix_0_5_10 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "43" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_10
+ )
+
+ @metadata_hash_prefix_0_5_10 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7826" <> <<_::binary-size(76)>> <> "0057" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_10
+ )
+
+ @metadata_hash_prefix_0_5_10 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7827" <> <<_::binary-size(78)>> <> "0057" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_10
+ )
+
+ @metadata_hash_prefix_0_5_10 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7828" <> <<_::binary-size(80)>> <> "0058" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_10
+ )
+
+ @metadata_hash_prefix_0_5_10 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7829" <> <<_::binary-size(82)>> <> "0059" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_10
+ )
# Solidity >= 0.5.11 https://github.com/ethereum/solidity/blob/develop/Changelog.md#0511-2019-08-12
# Metadata: Update the swarm hash to the current specification, changes bzzr0 to bzzr1 and urls to use bzz-raw://
- "a265627a7a72315820" <>
- <<_::binary-size(64)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments ->
- extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code, contract_name)
+ @metadata_hash_prefix_0_5_11 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "43" <> <<_::binary-size(6)>> <> "0032" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_11
+ )
+
+ @metadata_hash_prefix_0_5_11 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7826" <> <<_::binary-size(76)>> <> "0057" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_11
+ )
+
+ @metadata_hash_prefix_0_5_11 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7827" <> <<_::binary-size(78)>> <> "0057" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_11
+ )
+
+ @metadata_hash_prefix_0_5_11 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7828" <> <<_::binary-size(80)>> <> "0058" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_11
+ )
+
+ @metadata_hash_prefix_0_5_11 <>
+ <<_::binary-size(64)>> <>
+ @metadata_hash_common_suffix <> "7829" <> <<_::binary-size(82)>> <> "0059" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_5_11
+ )
# Solidity >= 0.6.0 https://github.com/ethereum/solidity/blob/develop/Changelog.md#060-2019-12-17
# https://github.com/ethereum/solidity/blob/26b700771e9cc9c956f0503a05de69a1be427963/docs/metadata.rst#encoding-of-the-metadata-hash-in-the-bytecode
@@ -58,9 +174,60 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
# 0x00 0x32
# Note: there is a bug in the docs. Instead of 0x32, 0x33 should be used.
# Fixing PR has been created https://github.com/ethereum/solidity/pull/8174
- "a264697066735822" <>
- <<_::binary-size(68)>> <> "64736f6c6343" <> <<_::binary-size(6)>> <> "0033" <> constructor_arguments ->
- extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code, contract_name)
+ @metadata_hash_prefix_0_6_0 <>
+ <<_::binary-size(68)>> <>
+ @metadata_hash_common_suffix <> "43" <> <<_::binary-size(6)>> <> "0033" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_6_0
+ )
+
+ @metadata_hash_prefix_0_6_0 <>
+ <<_::binary-size(68)>> <>
+ @metadata_hash_common_suffix <> "7826" <> <<_::binary-size(76)>> <> "0057" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_6_0
+ )
+
+ @metadata_hash_prefix_0_6_0 <>
+ <<_::binary-size(68)>> <>
+ @metadata_hash_common_suffix <> "7827" <> <<_::binary-size(78)>> <> "0057" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_6_0
+ )
+
+ @metadata_hash_prefix_0_6_0 <>
+ <<_::binary-size(68)>> <>
+ @metadata_hash_common_suffix <> "7828" <> <<_::binary-size(80)>> <> "0058" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_6_0
+ )
+
+ @metadata_hash_prefix_0_6_0 <>
+ <<_::binary-size(68)>> <>
+ @metadata_hash_common_suffix <> "7829" <> <<_::binary-size(82)>> <> "0059" <> constructor_arguments ->
+ split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ @metadata_hash_prefix_0_6_0
+ )
<<>> ->
check_func.("")
@@ -70,6 +237,35 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
end
end
+ defp is_constructor_arguments_still_has_metadata_prefix(constructor_arguments, prefix) do
+ constructor_arguments_parts =
+ constructor_arguments
+ |> String.split(prefix)
+ |> Enum.count()
+
+ constructor_arguments_parts > 1
+ end
+
+ defp split_constructor_arguments_and_extract_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name,
+ metadata_hash_prefix
+ ) do
+ if is_constructor_arguments_still_has_metadata_prefix(constructor_arguments, metadata_hash_prefix) do
+ <<_::binary-size(2)>> <> rest = constructor_arguments
+ extract_constructor_arguments(rest, check_func, contract_source_code, contract_name)
+ else
+ extract_constructor_arguments_check_func(
+ constructor_arguments,
+ check_func,
+ contract_source_code,
+ contract_name
+ )
+ end
+ end
+
defp extract_constructor_arguments_check_func(constructor_arguments, check_func, contract_source_code, contract_name) do
constructor_arguments =
remove_require_messages_from_constructor_arguments(contract_source_code, constructor_arguments, contract_name)
@@ -195,11 +391,17 @@ defmodule Explorer.SmartContract.Verifier.ConstructorArguments do
def find_all_requires(contract_source_code) do
if contract_source_code do
- [_ | requires] = String.split(contract_source_code, "require")
+ trimmed_source_code =
+ contract_source_code
+ |> String.replace(~r/ +/, " ")
+ |> String.replace("require(", "require (")
+
+ [_ | requires] =
+ trimmed_source_code
+ |> String.split("require (")
Enum.reduce(requires, [], fn right_from_require, requires_list ->
- [_ | [right_from_require_inside]] = String.split(right_from_require, "(", parts: 2)
- [require_content | _] = String.split(right_from_require_inside, ");", parts: 2)
+ [require_content | _] = String.split(right_from_require, ");", parts: 2)
[require_content | requires_list]
end)
else
diff --git a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex b/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex
index bde63ee1e9..b9d8adfc36 100644
--- a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex
+++ b/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex
@@ -98,10 +98,16 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
defp fetch_metadata(token_uri) do
case HTTPoison.get(token_uri) do
- {:ok, %Response{body: body, status_code: 200}} ->
- {:ok, json} = decode_json(body)
+ {:ok, %Response{body: body, status_code: 200, headers: headers}} ->
+ if Enum.member?(headers, {"Content-Type", "image/png"}) do
+ json = %{"image" => token_uri}
- check_type(json)
+ check_type(json)
+ else
+ {:ok, json} = decode_json(body)
+
+ check_type(json)
+ end
{:ok, %Response{body: body}} ->
{:error, body}
diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs
index 99626e0945..1c4cbd8e5e 100644
--- a/apps/explorer/mix.exs
+++ b/apps/explorer/mix.exs
@@ -84,7 +84,7 @@ defmodule Explorer.Mixfile do
# Code coverage
{:excoveralls, "~> 0.10.0", only: [:test], github: "KronicDeth/excoveralls", branch: "circle-workflows"},
{:exvcr, "~> 0.10", only: :test},
- {:httpoison, "~> 1.0"},
+ {:httpoison, "~> 1.6"},
{:jason, "~> 1.0"},
{:junit_formatter, ">= 0.0.0", only: [:test], runtime: false},
# Log errors and application output to separate files
diff --git a/apps/explorer/package-lock.json b/apps/explorer/package-lock.json
index 2c3c20aed5..b1ab348051 100644
--- a/apps/explorer/package-lock.json
+++ b/apps/explorer/package-lock.json
@@ -8,14 +8,6 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
- "bindings": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
- "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
- "requires": {
- "file-uri-to-path": "1.0.0"
- }
- },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -26,9 +18,9 @@
}
},
"command-exists": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz",
- "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw=="
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
+ "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
},
"commander": {
"version": "3.0.2",
@@ -40,11 +32,6 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
- "file-uri-to-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
- "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
- },
"fs-extra": {
"version": "0.30.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
@@ -76,9 +63,9 @@
}
},
"graceful-fs": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
- "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"inflight": {
"version": "1.0.6",
@@ -107,17 +94,6 @@
"graceful-fs": "^4.1.6"
}
},
- "keccak": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.0.0.tgz",
- "integrity": "sha512-rKe/lRr0KGhjoz97cwg+oeT1Rj/Y4cjae6glArioUC8JBF9ROGZctwIaaruM7d7naovME4Q8WcQSO908A8qcyQ==",
- "requires": {
- "bindings": "^1.2.1",
- "inherits": "^2.0.3",
- "nan": "^2.2.1",
- "safe-buffer": "^5.1.0"
- }
- },
"klaw": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
@@ -139,11 +115,6 @@
"brace-expansion": "^1.1.7"
}
},
- "nan": {
- "version": "2.14.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
- "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
- },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -175,20 +146,15 @@
"glob": "^7.1.3"
}
},
- "safe-buffer": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
- "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
- },
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"solc": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/solc/-/solc-0.6.1.tgz",
- "integrity": "sha512-iKqNYps2p++x8L9sBg7JeAJb7EmW8VJ/2asAzwlLYcUhj86AzuWLe94UTSQHv1SSCCj/x6lya8twvXkZtlTbIQ==",
+ "version": "0.6.7",
+ "resolved": "https://registry.npmjs.org/solc/-/solc-0.6.7.tgz",
+ "integrity": "sha512-a3iocjS1yGzw3Wy7jkqSLX3Vg1lMDCyoKZoVfpOagRGWkh37f11BrcUDO8f73rjdpw2WUBSLJtTQ26i52/0JOg==",
"requires": {
"command-exists": "^1.2.8",
"commander": "3.0.2",
diff --git a/apps/explorer/package.json b/apps/explorer/package.json
index 8fdead7f1d..995b1fb7d2 100644
--- a/apps/explorer/package.json
+++ b/apps/explorer/package.json
@@ -13,7 +13,6 @@
},
"scripts": {},
"dependencies": {
- "keccak": "^2.0.0",
- "solc": "^0.6.1"
+ "solc": "^0.6.7"
}
}
diff --git a/apps/explorer/priv/compile_solc.js b/apps/explorer/priv/compile_solc.js
index e6ba69c300..98f1b8bcfc 100755
--- a/apps/explorer/priv/compile_solc.js
+++ b/apps/explorer/priv/compile_solc.js
@@ -1,13 +1,12 @@
#!/usr/bin/env node
var sourceCodePath = process.argv[2];
-var version = process.argv[3];
+var compilerVersionPath = process.argv[3];
var optimize = process.argv[4];
var optimizationRuns = parseInt(process.argv[5], 10);
var newContractName = process.argv[6];
var externalLibraries = JSON.parse(process.argv[7])
var evmVersion = process.argv[8];
-var compilerVersionPath = process.argv[9];
var solc = require('solc')
var compilerSnapshot = require(compilerVersionPath);
diff --git a/apps/explorer/priv/repo/migrations/20200518075748_create_index_blocks_miner_hash_number_index.exs b/apps/explorer/priv/repo/migrations/20200518075748_create_index_blocks_miner_hash_number_index.exs
new file mode 100644
index 0000000000..f48ff9bbf0
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20200518075748_create_index_blocks_miner_hash_number_index.exs
@@ -0,0 +1,7 @@
+defmodule Explorer.Repo.Migrations.CreateIndexBlocksMinerHashNumberIndex do
+ use Ecto.Migration
+
+ def change do
+ create_if_not_exists(index(:blocks, [:miner_hash, :number]))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20200521170002_create_token_transfers_token_contract_address_hash_token_id_block_number_index.exs b/apps/explorer/priv/repo/migrations/20200521170002_create_token_transfers_token_contract_address_hash_token_id_block_number_index.exs
new file mode 100644
index 0000000000..eb136b3f22
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20200521170002_create_token_transfers_token_contract_address_hash_token_id_block_number_index.exs
@@ -0,0 +1,7 @@
+defmodule Explorer.Repo.Migrations.CreateTokenTransfersTokenContractAddressHashTokenIdBlockNumberIndex do
+ use Ecto.Migration
+
+ def change do
+ create_if_not_exists(index(:token_transfers, [:token_contract_address_hash, "token_id DESC", "block_number DESC"]))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20200525115811_address_coin_balances_daily.exs b/apps/explorer/priv/repo/migrations/20200525115811_address_coin_balances_daily.exs
new file mode 100644
index 0000000000..dc03899679
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20200525115811_address_coin_balances_daily.exs
@@ -0,0 +1,17 @@
+defmodule Explorer.Repo.Migrations.AddressCoinBalancesDaily do
+ use Ecto.Migration
+
+ def change do
+ create table(:address_coin_balances_daily, primary_key: false) do
+ add(:address_hash, references(:addresses, column: :hash, type: :bytea), null: false)
+ add(:day, :date, null: false)
+
+ # null until fetched
+ add(:value, :numeric, precision: 100, default: fragment("NULL"), null: true)
+
+ timestamps(null: false, type: :utc_datetime_usec)
+ end
+
+ create(unique_index(:address_coin_balances_daily, [:address_hash, :day]))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20200527144742_add_counters_table.exs b/apps/explorer/priv/repo/migrations/20200527144742_add_counters_table.exs
new file mode 100644
index 0000000000..e09b9ee1e7
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20200527144742_add_counters_table.exs
@@ -0,0 +1,12 @@
+defmodule Explorer.Repo.Migrations.AddCountersTable do
+ use Ecto.Migration
+
+ def change do
+ create table(:last_fetched_counters, primary_key: false) do
+ add(:counter_type, :string, primary_key: true, null: false)
+ add(:value, :numeric, precision: 100, null: true)
+
+ timestamps(null: false, type: :utc_datetime_usec)
+ end
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20200608075122_alter_transactions_add_error_reason.exs b/apps/explorer/priv/repo/migrations/20200608075122_alter_transactions_add_error_reason.exs
new file mode 100644
index 0000000000..6f0ab6320e
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20200608075122_alter_transactions_add_error_reason.exs
@@ -0,0 +1,9 @@
+defmodule Explorer.Repo.Migrations.AlterTransactionsAddErrorReason do
+ use Ecto.Migration
+
+ def change do
+ alter table(:transactions) do
+ add(:revert_reason, :text)
+ end
+ end
+end
diff --git a/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs b/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs
index a40cd8599e..a35fbcc578 100644
--- a/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs
+++ b/apps/explorer/test/explorer/chain/import/runner/address/token_balances_test.exs
@@ -93,7 +93,7 @@ defmodule Explorer.Chain.Import.Runner.Address.TokenBalancesTest do
value_fetched_at: DateTime.utc_now()
}
- run_changes(new_changes, options) |> IO.inspect()
+ run_changes(new_changes, options)
end
end
diff --git a/apps/explorer/test/explorer/chain/token_transfer_test.exs b/apps/explorer/test/explorer/chain/token_transfer_test.exs
index b388fafcbe..f82ab71323 100644
--- a/apps/explorer/test/explorer/chain/token_transfer_test.exs
+++ b/apps/explorer/test/explorer/chain/token_transfer_test.exs
@@ -156,6 +156,12 @@ defmodule Explorer.Chain.TokenTransferTest do
|> insert()
|> with_block(insert(:block, number: 1))
+ insert(
+ :token_instance,
+ token_id: 42,
+ token_contract_address_hash: token_contract_address.hash
+ )
+
insert(
:token_transfer,
to_address: build(:address),
@@ -168,7 +174,7 @@ defmodule Explorer.Chain.TokenTransferTest do
another_transaction =
:transaction
|> insert()
- |> with_block(insert(:block, number: 2))
+ |> with_block(insert(:block, number: 3))
last_owner =
insert(
diff --git a/apps/explorer/test/explorer/chain_spec/parity/importer_test.exs b/apps/explorer/test/explorer/chain_spec/parity/importer_test.exs
index ba97a94731..2f19675c43 100644
--- a/apps/explorer/test/explorer/chain_spec/parity/importer_test.exs
+++ b/apps/explorer/test/explorer/chain_spec/parity/importer_test.exs
@@ -1,12 +1,17 @@
defmodule Explorer.ChainSpec.Parity.ImporterTest do
use Explorer.DataCase
- alias Explorer.Chain.Address.CoinBalance
+ import Mox
+ import EthereumJSONRPC, only: [integer_to_quantity: 1]
+
+ alias Explorer.Chain.Address.{CoinBalance, CoinBalanceDaily}
alias Explorer.Chain.Block.{EmissionReward, Range}
alias Explorer.Chain.{Address, Hash, Wei}
alias Explorer.ChainSpec.Parity.Importer
alias Explorer.Repo
+ setup :set_mox_global
+
@chain_spec "#{File.cwd!()}/test/support/fixture/chain_spec/foundation.json"
|> File.read!()
|> Jason.decode!()
@@ -141,14 +146,37 @@ defmodule Explorer.ChainSpec.Parity.ImporterTest do
describe "import_genesis_accounts/1" do
test "imports accounts" do
+ block_quantity = integer_to_quantity(1)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{id: 0, jsonrpc: "2.0", method: "eth_getBlockByNumber", params: ["0x1", true]}
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
{:ok, %{address_coin_balances: address_coin_balances}} = Importer.import_genesis_accounts(@chain_spec)
assert Enum.count(address_coin_balances) == 403
assert CoinBalance |> Repo.all() |> Enum.count() == 403
+ assert CoinBalanceDaily |> Repo.all() |> Enum.count() == 403
assert Address |> Repo.all() |> Enum.count() == 403
end
test "imports contract code" do
+ block_quantity = integer_to_quantity(1)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{id: 0, jsonrpc: "2.0", method: "eth_getBlockByNumber", params: ["0x1", true]}
+ ],
+ [] ->
+ {:ok, [res]}
+ end)
+
code =
"0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c806391ad27b41161008c57806398d5fdca1161006657806398d5fdca14610262578063a97e5c9314610280578063df5dd1a5146102dc578063eebd48b014610320576100cf565b806391ad27b4146101e457806391b7f5ed14610202578063955d14cd14610244576100cf565b80630aa6f2fe146100d457806320ba81ee1461011657806322a90082146101345780634c2c987c14610176578063764cbcd1146101985780637837efdc146101da575b600080fd5b610100600480360360208110156100ea57600080fd5b8101908080359060200190929190505050610353565b6040518082815260200191505060405180910390f35b61011e6103c4565b6040518082815260200191505060405180910390f35b6101606004803603602081101561014a57600080fd5b81019080803590602001909291905050506103ce565b6040518082815260200191505060405180910390f35b61017e61043f565b604051808215151515815260200191505060405180910390f35b6101c4600480360360208110156101ae57600080fd5b8101908080359060200190929190505050610456565b6040518082815260200191505060405180910390f35b6101e26104c7565b005b6101ec6104d2565b6040518082815260200191505060405180910390f35b61022e6004803603602081101561021857600080fd5b81019080803590602001909291905050506104dc565b6040518082815260200191505060405180910390f35b61024c6106a2565b6040518082815260200191505060405180910390f35b61026a6106ac565b6040518082815260200191505060405180910390f35b6102c26004803603602081101561029657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506106b6565b604051808215151515815260200191505060405180910390f35b61031e600480360360208110156102f257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506106d3565b005b61032861073d565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b600061035e336106b6565b6103b3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180610b4f6030913960400191505060405180910390fd5b816004819055506004549050919050565b6000600454905090565b60006103d9336106b6565b61042e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180610b4f6030913960400191505060405180910390fd5b816003819055506003549050919050565b6000600560009054906101000a900460ff16905090565b6000610461336106b6565b6104b6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180610b4f6030913960400191505060405180910390fd5b816002819055506002549050919050565b6104d033610771565b565b6000600354905090565b60006104e7336106b6565b61053c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180610b4f6030913960400191505060405180910390fd5b600082116105b2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260098152602001807f7072696365203c3d30000000000000000000000000000000000000000000000081525060200191505060405180910390fd5b6105ba6104d2565b6105c26106a2565b01421015610638576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f54494d455f4c4f434b5f494e434f4d504c45544500000000000000000000000081525060200191505060405180910390fd5b610641826107cb565b5061064b42610456565b503373ffffffffffffffffffffffffffffffffffffffff167f95dce27040c59c8b1c445b284f81a3aaae6eecd7d08d5c7684faee64cdb514a1836040518082815260200191505060405180910390a2819050919050565b6000600254905090565b6000600154905090565b60006106cc82600061083c90919063ffffffff16565b9050919050565b6106dc336106b6565b610731576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180610b4f6030913960400191505060405180910390fd5b61073a8161091a565b50565b60008060008061074b6106ac565b6107536104d2565b61075b6103c4565b6107636106a2565b935093509350935090919293565b61078581600061097390919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167f9c8e7d83025bef8a04c664b2f753f64b8814bdb7e27291d7e50935f18cc3c71260405160405180910390a250565b60006107d6336106b6565b61082b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180610b4f6030913960400191505060405180910390fd5b816001819055506001549050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156108c3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610b2d6022913960400191505060405180910390fd5b8260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b61092e816000610a3090919063ffffffff16565b8073ffffffffffffffffffffffffffffffffffffffff167e47706786c922d17b39285dc59d696bafea72c0b003d3841ae1202076f4c2e460405160405180910390a250565b61097d828261083c565b6109d2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180610b0c6021913960400191505060405180910390fd5b60008260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b610a3a828261083c565b15610aad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650081525060200191505060405180910390fd5b60018260000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550505056fe526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c65526f6c65733a206163636f756e7420697320746865207a65726f20616464726573734f7261636c65526f6c653a2063616c6c657220646f6573206e6f74206861766520746865204f7261636c6520726f6c65a265627a7a72315820df30730da57a5061c487e0b37e84e80308fa443e2e80ee9117a13fa8149caf4164736f6c634300050b0032"
@@ -169,11 +197,59 @@ defmodule Explorer.ChainSpec.Parity.ImporterTest do
end
test "imports coin balances without 0x" do
+ block_quantity = integer_to_quantity(1)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{id: 0, jsonrpc: "2.0", method: "eth_getBlockByNumber", params: ["0x1", true]}
+ ],
+ [] ->
+ {:ok, [res]}
+ end)
+
{:ok, %{address_coin_balances: address_coin_balances}} = Importer.import_genesis_accounts(@chain_classic_spec)
assert Enum.count(address_coin_balances) == 8894
assert CoinBalance |> Repo.all() |> Enum.count() == 8894
+ assert CoinBalanceDaily |> Repo.all() |> Enum.count() == 8894
assert Address |> Repo.all() |> Enum.count() == 8894
end
end
+
+ defp eth_block_number_fake_response(block_quantity) do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x0000000000000000000000000000000000000000",
+ "difficulty" => "0x20000",
+ "extraData" => "0x",
+ "gasLimit" => "0x663be0",
+ "gasUsed" => "0x0",
+ "hash" => "0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x0000000000000000000000000000000000000000",
+ "number" => block_quantity,
+ "parentHash" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x80",
+ "0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "size" => "0x215",
+ "stateRoot" => "0xfad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3",
+ "step" => "0",
+ "timestamp" => "0x0",
+ "totalDifficulty" => "0x20000",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ end
end
diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs
index ade78e9f64..ed6d37aaa4 100644
--- a/apps/explorer/test/explorer/chain_test.exs
+++ b/apps/explorer/test/explorer/chain_test.exs
@@ -4719,6 +4719,8 @@ defmodule Explorer.ChainTest do
block_one_day_ago = insert(:block, timestamp: yesterday, number: 49)
insert(:fetched_balance, address_hash: address.hash, value: 1000, block_number: block.number)
insert(:fetched_balance, address_hash: address.hash, value: 2000, block_number: block_one_day_ago.number)
+ insert(:fetched_balance_daily, address_hash: address.hash, value: 1000, day: noon)
+ insert(:fetched_balance_daily, address_hash: address.hash, value: 2000, day: yesterday)
balances = Chain.address_to_balances_by_day(address.hash)
@@ -4735,6 +4737,7 @@ defmodule Explorer.ChainTest do
yesterday = Timex.shift(noon, days: -1)
block_one_day_ago = insert(:block, timestamp: yesterday)
insert(:fetched_balance, address_hash: address.hash, value: 1000, block_number: block_one_day_ago.number)
+ insert(:fetched_balance_daily, address_hash: address.hash, value: 1000, day: yesterday)
balances = Chain.address_to_balances_by_day(address.hash)
@@ -4754,6 +4757,7 @@ defmodule Explorer.ChainTest do
block_past = insert(:block, timestamp: past, number: 2)
insert(:fetched_balance, address_hash: address.hash, value: 0, block_number: block_past.number)
+ insert(:fetched_balance_daily, address_hash: address.hash, value: 0, day: today)
[balance] = Chain.address_to_balances_by_day(address.hash)
@@ -5021,32 +5025,6 @@ defmodule Explorer.ChainTest do
end
end
- describe "address_to_coin_balances/2" do
- test "deduplicates records by zero delta" do
- address = insert(:address)
-
- 1..5
- |> Enum.each(fn block_number ->
- insert(:block, number: block_number)
- insert(:fetched_balance, value: 1, block_number: block_number, address_hash: address.hash)
- end)
-
- insert(:block, number: 6)
- insert(:fetched_balance, value: 2, block_number: 6, address_hash: address.hash)
-
- assert [first, second, third] = Chain.address_to_coin_balances(address.hash, [])
-
- assert first.block_number == 6
- assert first.delta == Decimal.new(1)
-
- assert second.block_number == 5
- assert second.delta == Decimal.new(0)
-
- assert third.block_number == 1
- assert third.delta == Decimal.new(1)
- end
- end
-
describe "extract_db_name/1" do
test "extracts correct db name" do
db_url = "postgresql://viktor:@localhost:5432/blockscout-dev-1"
@@ -5187,4 +5165,32 @@ defmodule Explorer.ChainTest do
}
end
end
+
+ describe "transaction_to_revert_reason/1" do
+ test "returns correct revert_reason from DB" do
+ transaction = insert(:transaction, revert_reason: "No credit of that type")
+ assert Chain.transaction_to_revert_reason(transaction) == "No credit of that type"
+ end
+
+ test "returns correct revert_reason from the archive node" do
+ transaction =
+ insert(:transaction,
+ gas: 27319,
+ gas_price: "0x1b31d2900",
+ value: "0x86b3",
+ input: %Explorer.Chain.Data{bytes: <<1>>}
+ )
+ |> with_block(insert(:block, number: 1))
+
+ expect(
+ EthereumJSONRPC.Mox,
+ :json_rpc,
+ fn _json, [] ->
+ {:error, %{code: -32015, message: "VM execution error.", data: "revert: No credit of that type"}}
+ end
+ )
+
+ assert Chain.transaction_to_revert_reason(transaction) == "No credit of that type"
+ end
+ end
end
diff --git a/apps/explorer/test/explorer/smart_contract/publisher_test.exs b/apps/explorer/test/explorer/smart_contract/publisher_test.exs
index 79fbe55f63..4933a7a4e5 100644
--- a/apps/explorer/test/explorer/smart_contract/publisher_test.exs
+++ b/apps/explorer/test/explorer/smart_contract/publisher_test.exs
@@ -14,6 +14,7 @@ defmodule Explorer.SmartContract.PublisherTest do
contract_code_info = Factory.contract_code_info()
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input)
valid_attrs = %{
"contract_source_code" => contract_code_info.source_code,
@@ -44,12 +45,15 @@ defmodule Explorer.SmartContract.PublisherTest do
bytecode =
"0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820fe0ba5210ac95870683c2cb054304b04565703bd16c7d7e956df694c9643c6d264736f6c63430005090032"
+ input =
+ "0x60806040526040518060400160405280600381526020017f302e3100000000000000000000000000000000000000000000000000000000008152506006908051906020019062000051929190620001e2565b503480156200005f57600080fd5b506040516200105b3803806200105b833981810160405260808110156200008557600080fd5b81019080805190602001909291908051640100000000811115620000a857600080fd5b82810190506020810184811115620000bf57600080fd5b8151856001820283011164010000000082111715620000dd57600080fd5b50509291906020018051906020019092919080516401000000008111156200010457600080fd5b828101905060208101848111156200011b57600080fd5b81518560018202830111640100000000821117156200013957600080fd5b5050929190505050836000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550836002819055508260039080519060200190620001a3929190620001e2565b5081600460006101000a81548160ff021916908360ff1602179055508060059080519060200190620001d7929190620001e2565b505050505062000291565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200022557805160ff191683800117855562000256565b8280016001018555821562000256579182015b828111156200025557825182559160200191906001019062000238565b5b50905062000265919062000269565b5090565b6200028e91905b808211156200028a57600081600090555060010162000270565b5090565b90565b610dba80620002a16000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820c63b805fe76ce64d7ba5aedfa99bbfa5b13cc8c2fabad31b2364f8ae421cd40c64736f6c63430005090032"
+
contract_address = insert(:contract_address, contract_code: bytecode)
:transaction
|> insert(
created_contract_address_hash: contract_address.hash,
- input: bytecode <> expected_constructor_arguments
+ input: input <> expected_constructor_arguments
)
|> with_block()
@@ -70,6 +74,7 @@ defmodule Explorer.SmartContract.PublisherTest do
contract_code_info = Factory.contract_code_info()
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input)
valid_attrs = %{
"contract_source_code" => contract_code_info.source_code,
@@ -106,7 +111,7 @@ defmodule Explorer.SmartContract.PublisherTest do
:transaction
|> insert(
created_contract_address_hash: contract_address.hash,
- input: contract_code_info.bytecode <> constructor_arguments
+ input: contract_code_info.tx_input <> constructor_arguments
)
|> with_block()
@@ -142,8 +147,10 @@ defmodule Explorer.SmartContract.PublisherTest do
optimize = contract_data["optimize"]
contract = contract_data["contract"]
expected_bytecode = contract_data["expected_bytecode"]
+ tx_input = contract_data["tx_input"]
contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input)
params = %{
"contract_source_code" => contract,
diff --git a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
index 29674274ca..8d092d66bf 100644
--- a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
+++ b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs
@@ -92,9 +92,9 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
)
clean_result = remove_init_data_and_whisper_data(result["bytecode"])
- expected_result = remove_init_data_and_whisper_data(compiler_test["expected_bytecode"])
+ expected_result = remove_init_data_and_whisper_data(compiler_test["tx_input"])
- assert clean_result == expected_result
+ assert expected_result == clean_result
end)
end
@@ -166,7 +166,7 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do
}
"""
- version = "v0.1.3-nightly.2015.9.25+commit.4457170"
+ version = "v0.1.3+commit.028f561d"
response = CodeCompiler.run(name: name, compiler_version: version, code: code, optimize: optimize)
diff --git a/apps/explorer/test/explorer/smart_contract/verifier_test.exs b/apps/explorer/test/explorer/smart_contract/verifier_test.exs
index 1fdbc2331b..73be0078fa 100644
--- a/apps/explorer/test/explorer/smart_contract/verifier_test.exs
+++ b/apps/explorer/test/explorer/smart_contract/verifier_test.exs
@@ -7,6 +7,57 @@ defmodule Explorer.SmartContract.VerifierTest do
alias Explorer.SmartContract.Verifier
alias Explorer.Factory
+ @code_0_4 """
+ pragma solidity ^0.4.0;
+ contract Incrementer {
+ event Incremented(address indexed sender, uint256 newValue);
+ uint256 public value;
+ address public lastSender;
+ constructor(uint256 initialValue) public {
+ value = initialValue;
+ lastSender = msg.sender;
+ }
+ function inc(uint256 delta) public {
+ value = value + delta;
+ lastSender = msg.sender;
+ }
+ }
+ """
+
+ @code_0_5 """
+ pragma solidity ^0.5.0;
+ contract Incrementer {
+ event Incremented(address indexed sender, uint256 newValue);
+ uint256 public value;
+ address public lastSender;
+ constructor(uint256 initialValue) public {
+ value = initialValue;
+ lastSender = msg.sender;
+ }
+ function inc(uint256 delta) public {
+ value = value + delta;
+ lastSender = msg.sender;
+ }
+ }
+ """
+
+ @code_0_6 """
+ pragma solidity ^0.6.0;
+ contract Incrementer {
+ event Incremented(address indexed sender, uint256 newValue);
+ uint256 public value;
+ address public lastSender;
+ constructor(uint256 initialValue) public {
+ value = initialValue;
+ lastSender = msg.sender;
+ }
+ function inc(uint256 delta) public {
+ value = value + delta;
+ lastSender = msg.sender;
+ }
+ }
+ """
+
describe "evaluate_authenticity/2" do
setup do
{:ok, contract_code_info: Factory.contract_code_info()}
@@ -16,6 +67,7 @@ defmodule Explorer.SmartContract.VerifierTest do
contract_code_info: contract_code_info
} do
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: contract_code_info.tx_input)
params = %{
"contract_source_code" => contract_code_info.source_code,
@@ -41,8 +93,10 @@ defmodule Explorer.SmartContract.VerifierTest do
optimize = contract_data["optimize"]
contract = contract_data["contract"]
expected_bytecode = contract_data["expected_bytecode"]
+ tx_input = contract_data["tx_input"]
contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: "0x" <> tx_input)
params = %{
"contract_source_code" => contract,
@@ -68,9 +122,16 @@ defmodule Explorer.SmartContract.VerifierTest do
contract = contract_data["contract"]
expected_bytecode = contract_data["bytecode"]
evm_version = contract_data["evm_version"]
+ input = contract_data["input"]
contract_address = insert(:contract_address, contract_code: "0x" <> expected_bytecode)
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: "0x" <> input
+ )
+
params = %{
"contract_source_code" => contract,
"compiler_version" => compiler_version,
@@ -101,7 +162,7 @@ defmodule Explorer.SmartContract.VerifierTest do
:transaction
|> insert(
created_contract_address_hash: contract_address.hash,
- input: contract_code_info.bytecode <> constructor_arguments
+ input: contract_code_info.tx_input <> constructor_arguments
)
|> with_block()
@@ -111,7 +172,7 @@ defmodule Explorer.SmartContract.VerifierTest do
test "tries to compile with the latest evm version if wrong evm version was provided" do
bytecode =
- "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063256fec88146100545780633fa4f245146100a9578063812600df146100d2575b600080fd5b341561005f57600080fd5b6100676100f5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100b457600080fd5b6100bc61011b565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b6100f36004808035906020019091905050610121565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a72305820b81379d1ae9d8e0fde05ee02b8bd170f43f8bd3d54da8b7ec203434a23a298980029"
+ "0x6060604052341561000f57600080fd5b604051602080610223833981016040528080519060200190919050505b8060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505b61019d806100866000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063256fec88146100545780633fa4f245146100a9578063812600df146100d2575b600080fd5b341561005f57600080fd5b6100676100f5565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156100b457600080fd5b6100bc61011b565b6040518082815260200191505060405180910390f35b34156100dd57600080fd5b6100f36004808035906020019091905050610121565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a723058201de7017582ff17d45730bc9aedeac5b399399b71b188f42a164609c1b6f7f4760029"
constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
@@ -156,9 +217,10 @@ defmodule Explorer.SmartContract.VerifierTest do
test "verifies a library" do
bytecode =
- "0x7349f540c22cba15c47a08c235e20081474201a742301460806040526004361060335760003560e01c8063c2985578146038575b600080fd5b603e60b0565b6040805160208082528351818301528351919283929083019185019080838360005b8381101560765781810151838201526020016060565b50505050905090810190601f16801560a25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080518082019091526003815262666f6f60e81b60208201529056fea265627a7a72315820174b282a3ef3b9778d79fbc2e4c36bc939c54dfaaaa51d3122ee6e648093844c64736f6c634300050b0032"
+ "0x610102610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063c2985578146038575b600080fd5b603e60b0565b6040805160208082528351818301528351919283929083019185019080838360005b8381101560765781810151838201526020016060565b50505050905090810190601f16801560a25780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080518082019091526003815262666f6f60e81b60208201529056fea265627a7a7231582079c18e1f9cf2812147d15e5d44f16ff748f8b7349d32dc9db50300a3ffbd3a9664736f6c634300050b0032"
contract_address = insert(:contract_address, contract_code: bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: bytecode)
code = """
pragma solidity 0.5.11;
@@ -192,12 +254,15 @@ defmodule Explorer.SmartContract.VerifierTest do
bytecode =
"0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820fe0ba5210ac95870683c2cb054304b04565703bd16c7d7e956df694c9643c6d264736f6c63430005090032"
+ input =
+ "0x60806040526040518060400160405280600381526020017f302e3100000000000000000000000000000000000000000000000000000000008152506006908051906020019062000051929190620001e2565b503480156200005f57600080fd5b506040516200105b3803806200105b833981810160405260808110156200008557600080fd5b81019080805190602001909291908051640100000000811115620000a857600080fd5b82810190506020810184811115620000bf57600080fd5b8151856001820283011164010000000082111715620000dd57600080fd5b50509291906020018051906020019092919080516401000000008111156200010457600080fd5b828101905060208101848111156200011b57600080fd5b81518560018202830111640100000000821117156200013957600080fd5b5050929190505050836000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550836002819055508260039080519060200190620001a3929190620001e2565b5081600460006101000a81548160ff021916908360ff1602179055508060059080519060200190620001d7929190620001e2565b505050505062000291565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200022557805160ff191683800117855562000256565b8280016001018555821562000256579182015b828111156200025557825182559160200191906001019062000238565b5b50905062000265919062000269565b5090565b6200028e91905b808211156200028a57600081600090555060010162000270565b5090565b90565b610dba80620002a16000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633177029f116100715780633177029f1461025f57806354fd4d50146102c557806370a082311461034857806395d89b41146103a0578063a9059cbb14610423578063dd62ed3e14610489576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b6610501565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059f565b604051808215151515815260200191505060405180910390f35b61019f610691565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610696565b604051808215151515815260200191505060405180910390f35b61024361090f565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610922565b604051808215151515815260200191505060405180910390f35b6102cd610a14565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030d5780820151818401526020810190506102f2565b50505050905090810190601f16801561033a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61038a6004803603602081101561035e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ab2565b6040518082815260200191505060405180910390f35b6103a8610afa565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e85780820151818401526020810190506103cd565b50505050905090810190601f1680156104155780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61046f6004803603604081101561043957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610b98565b604051808215151515815260200191505060405180910390f35b6104eb6004803603604081101561049f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610cfe565b6040518082815260200191505060405180910390f35b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156105975780601f1061056c57610100808354040283529160200191610597565b820191906000526020600020905b81548152906001019060200180831161057a57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b600090565b6000816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610762575081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b801561076e5750600082115b1561090357816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610908565b600090505b9392505050565b600460009054906101000a900460ff1681565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60068054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610aaa5780601f10610a7f57610100808354040283529160200191610aaa565b820191906000526020600020905b815481529060010190602001808311610a8d57829003601f168201915b505050505081565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610b905780601f10610b6557610100808354040283529160200191610b90565b820191906000526020600020905b815481529060010190602001808311610b7357829003601f168201915b505050505081565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410158015610be85750600082115b15610cf357816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610cf8565b600090505b92915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509291505056fea265627a7a72305820c63b805fe76ce64d7ba5aedfa99bbfa5b13cc8c2fabad31b2364f8ae421cd40c64736f6c63430005090032"
+
contract_address = insert(:contract_address, contract_code: bytecode)
:transaction
|> insert(
created_contract_address_hash: contract_address.hash,
- input: bytecode <> constructor_arguments
+ input: input <> constructor_arguments
)
|> with_block()
@@ -216,6 +281,7 @@ defmodule Explorer.SmartContract.VerifierTest do
test "returns error when bytecode doesn't match", %{contract_code_info: contract_code_info} do
contract_address = insert(:contract_address, contract_code: contract_code_info.bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash)
different_code = "pragma solidity ^0.4.24; contract SimpleStorage {}"
@@ -276,7 +342,7 @@ defmodule Explorer.SmartContract.VerifierTest do
end
end
- describe "extract_bytecode/1" do
+ describe "extract_bytecode_and_metadata_hash/1" do
test "extracts the bytecode from the hash" do
code =
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058203c381c1b48b38d050c54d7ef296ecd411040e19420dfec94772b9c49ae106a0b0029"
@@ -286,7 +352,10 @@ defmodule Explorer.SmartContract.VerifierTest do
bytecode =
"0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600"
- assert bytecode == Verifier.extract_bytecode(code)
+ %{"metadata_hash" => _metadata_hash, "bytecode" => bytecode_from_code, "compiler_version" => _compiler_version} =
+ Verifier.extract_bytecode_and_metadata_hash(code)
+
+ assert bytecode == bytecode_from_code
assert bytecode != code
assert String.contains?(code, bytecode) == true
assert String.contains?(bytecode, "0029") == false
@@ -302,11 +371,412 @@ defmodule Explorer.SmartContract.VerifierTest do
bytecode =
"0x608060405234801561001057600080fd5b5060df80610010029f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600"
- assert bytecode == Verifier.extract_bytecode(code)
+ %{"metadata_hash" => _metadata_hash, "bytecode" => bytecode_from_code, "compiler_version" => _compiler_version} =
+ Verifier.extract_bytecode_and_metadata_hash(code)
+
+ assert bytecode == bytecode_from_code
assert bytecode != code
assert String.contains?(code, bytecode) == true
assert String.contains?(bytecode, "0029") == true
assert String.contains?(bytecode, swarm_source) == false
end
+
+ # https://solidity.readthedocs.io/en/v0.6.6/contracts.html?highlight=immutable#constant-and-immutable-state-variables
+ test "verifies smart-contract with `immutable` assignment" do
+ bytecode =
+ "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063fb49908514602d575b600080fd5b605060048036036020811015604157600080fd5b50356001600160a01b03166064565b604080519115158252519081900360200190f35b7f0000000000000000000000000000000000000000000000056b3977a93ae7c2006001600160a01b038216311191905056fea2646970667358221220b4fbf35809f2d1b85699a897ebb75d00c8c26b29b72decc53db18ddbd853352164736f6c63430006070033"
+
+ tx_input =
+ "0x60e06040523360601b60c05234801561001757600080fd5b5060405161013f38038061013f8339818101604052604081101561003a57600080fd5b50805160209091015160808290526001600160a01b03163160a081905260c05160601c60cc6100736000395080606652505060cc6000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063fb49908514602d575b600080fd5b605060048036036020811015604157600080fd5b50356001600160a01b03166064565b604080519115158252519081900360200190f35b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038216311191905056fea2646970667358221220b4fbf35809f2d1b85699a897ebb75d00c8c26b29b72decc53db18ddbd853352164736f6c63430006070033000000000000000000000000000000000000000000000000000000000000000100000000000000000000000023602745048d3b8d0a7f953ad444da4cd237ac83"
+
+ contract_address = insert(:contract_address, contract_code: bytecode)
+ insert(:transaction, created_contract_address_hash: contract_address.hash, input: tx_input)
+
+ code = """
+ pragma solidity >0.6.4 <0.7.0;
+
+ contract C {
+ uint constant X = 32**22 + 8;
+ string constant TEXT = "abc";
+ bytes32 constant MY_HASH = keccak256("abc");
+ uint immutable decimals;
+ uint immutable maxBalance;
+ address immutable owner = msg.sender;
+
+ constructor(uint _decimals, address _reference) public {
+ decimals = _decimals;
+ // Assignments to immutables can even access the environment.
+ maxBalance = _reference.balance;
+ }
+
+ function isBalanceTooHigh(address _other) public view returns (bool) {
+ return _other.balance > maxBalance;
+ }
+ }
+ """
+
+ constructor_arguments =
+ "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000023602745048d3b8d0a7f953ad444da4cd237ac83"
+
+ params = %{
+ "contract_source_code" => code,
+ "compiler_version" => "v0.6.7+commit.b8d736ae",
+ "evm_version" => "default",
+ "name" => "C",
+ "optimization" => true,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verifies smart-contract created from another contract" do
+ path = File.cwd!() <> "/test/support/fixture/smart_contract/contract_from_factory.sol"
+ contract = File.read!(path)
+
+ constructor_arguments = "4e1477bdc40fc2458bf646f96f269502658277779fdf0f4080fe798a2d45bc37"
+
+ bytecode =
+ "0x608060405260043610603e5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416638052474d81146043575b600080fd5b348015604e57600080fd5b5060556067565b60408051918252519081900360200190f35b600054815600a165627a7a72305820a1a0ec90e133c3064fab0ae82aa02a020224ea39d2b5421b6788f800bdde02f60029"
+
+ init =
+ "0x608060405234801561001057600080fd5b506040516020806100cc83398101604052516000556099806100336000396000f300608060405260043610603e5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416638052474d81146043575b600080fd5b348015604e57600080fd5b5060556067565b60408051918252519081900360200190f35b600054815600a165627a7a72305820a1a0ec90e133c3064fab0ae82aa02a020224ea39d2b5421b6788f800bdde02f600294e1477bdc40fc2458bf646f96f269502658277779fdf0f4080fe798a2d45bc37"
+
+ contract_address = insert(:contract_address, contract_code: bytecode)
+
+ transaction_success_details = [
+ status: :ok
+ ]
+
+ transaction =
+ :transaction
+ |> insert()
+ |> with_block(transaction_success_details)
+
+ :internal_transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ init: init,
+ type: "create",
+ created_contract_code: bytecode,
+ input: nil,
+ transaction_hash: transaction.hash,
+ index: 0,
+ block_hash: transaction.block_hash,
+ block_index: 0
+ )
+
+ params = %{
+ "contract_source_code" => contract,
+ "compiler_version" => "v0.4.26+commit.4563c3fc",
+ "evm_version" => "default",
+ "name" => "ContractFromFactory",
+ "optimization" => true,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verifies smart-contract created from another contract using successful tx" do
+ path = File.cwd!() <> "/test/support/fixture/smart_contract/contract_from_factory.sol"
+ contract = File.read!(path)
+
+ constructor_arguments = "4e1477bdc40fc2458bf646f96f269502658277779fdf0f4080fe798a2d45bc37"
+
+ bytecode =
+ "0x608060405260043610603e5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416638052474d81146043575b600080fd5b348015604e57600080fd5b5060556067565b60408051918252519081900360200190f35b600054815600a165627a7a72305820a1a0ec90e133c3064fab0ae82aa02a020224ea39d2b5421b6788f800bdde02f60029"
+
+ init =
+ "0x608060405234801561001057600080fd5b506040516020806100cc83398101604052516000556099806100336000396000f300608060405260043610603e5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416638052474d81146043575b600080fd5b348015604e57600080fd5b5060556067565b60408051918252519081900360200190f35b600054815600a165627a7a72305820a1a0ec90e133c3064fab0ae82aa02a020224ea39d2b5421b6788f800bdde02f600294e1477bdc40fc2458bf646f96f269502658277779fdf0f4080fe798a2d45bc37"
+
+ contract_address = insert(:contract_address, contract_code: bytecode)
+
+ transaction_success_details = [
+ status: :ok
+ ]
+
+ transaction_success =
+ :transaction
+ |> insert()
+ |> with_block(transaction_success_details)
+
+ transaction_failure_details = [
+ status: :error
+ ]
+
+ transaction_failure =
+ :transaction
+ |> insert()
+ |> with_block(transaction_failure_details)
+
+ :internal_transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ init: init,
+ type: "create",
+ created_contract_code: bytecode,
+ input: nil,
+ transaction_hash: transaction_success.hash,
+ index: 0,
+ block_hash: transaction_success.block_hash,
+ block_index: 0
+ )
+
+ :internal_transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ init: init,
+ type: "create",
+ created_contract_code: bytecode,
+ input: nil,
+ transaction_hash: transaction_failure.hash,
+ index: 0,
+ block_hash: transaction_failure.block_hash,
+ block_index: 0
+ )
+
+ params = %{
+ "contract_source_code" => contract,
+ "compiler_version" => "v0.4.26+commit.4563c3fc",
+ "evm_version" => "default",
+ "name" => "ContractFromFactory",
+ "optimization" => true,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+ end
+
+ describe "compiler version tests" do
+ test "verification is failed if wrong version of compiler" do
+ bytecode_0_5_10 =
+ "0x608060405234801561001057600080fd5b506040516102453803806102458339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101a98061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820fb47165501c50aae8ccb0394b15f4302606e0ba55eb6d59fe12eca19ba494d5e64736f6c634300050a0032"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_5_10)
+ bytecode_construtor_arguments = "#{bytecode_0_5_10}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_5,
+ "compiler_version" => "v0.5.11+commit.c082d0b4",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ response = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert {:error, :compiler_version} = response
+ end
+
+ test "verification is successful if proper version of compiler" do
+ bytecode_0_5_10 =
+ "0x608060405234801561001057600080fd5b506040516102453803806102458339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101a98061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820fb47165501c50aae8ccb0394b15f4302606e0ba55eb6d59fe12eca19ba494d5e64736f6c634300050a0032"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_5_10)
+ bytecode_construtor_arguments = "#{bytecode_0_5_10}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_5,
+ "compiler_version" => "v0.5.10+commit.5a6ea5b1",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+ end
+
+ describe "verification with nightly builds" do
+ test "verification is successful if proper nightly version of compiler ~0.4" do
+ bytecode_v0_4_24_nightly_2018_4_26_commit_ef2111a2 =
+ "0x608060405234801561001057600080fd5b5060405160208061023d833981018060405281019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101b28061008b6000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063256fec881461005c5780633fa4f245146100b3578063812600df146100de575b600080fd5b34801561006857600080fd5b5061007161010b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100bf57600080fd5b506100c8610131565b6040518082815260200191505060405180910390f35b3480156100ea57600080fd5b5061010960048036038101908080359060200190929190505050610137565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505600a165627a7a723058202d622d653be0a507f7ac0bc89d8934ccdbaf5e127abd603c3864a462149885070029"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_v0_4_24_nightly_2018_4_26_commit_ef2111a2)
+ bytecode_construtor_arguments = "#{bytecode_v0_4_24_nightly_2018_4_26_commit_ef2111a2}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_4,
+ "compiler_version" => "v0.4.24-nightly.2018.4.26+commit.ef2111a2",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verification is successful if proper nightly version of compiler ~0.5.10" do
+ bytecode_0_5_10_nightly_2019_6_4_commit_95e6b2e4 =
+ "0x608060405234801561001057600080fd5b5060405161026a38038061026a8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101ce8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a723058208d4e3fa9b2179a8384e617e388dde334be1b44e7b11b42ab964ab1050e7cedca64736f6c637827302e352e31302d6e696768746c792e323031392e362e342b636f6d6d69742e39356536623265340057"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_5_10_nightly_2019_6_4_commit_95e6b2e4)
+ bytecode_construtor_arguments = "#{bytecode_0_5_10_nightly_2019_6_4_commit_95e6b2e4}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_5,
+ "compiler_version" => "v0.5.10-nightly.2019.6.4+commit.95e6b2e4",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verification is successful if proper nightly version of compiler ~0.5.11" do
+ bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753 =
+ "0x608060405234801561001057600080fd5b5060405161026b38038061026b8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101cf8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820f7420b8c3b16d83ce728d8c279f0f887c4dcd7bfcd38c484acc9cdb82fde785764736f6c637828302e352e31312d6e696768746c792e323031392e362e32352b636f6d6d69742e31636338343735330058"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753)
+ bytecode_construtor_arguments = "#{bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_5,
+ "compiler_version" => "v0.5.11-nightly.2019.6.25+commit.1cc84753",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verification is successful if proper nightly version of compiler ~0.5.14" do
+ bytecode_0_5_14_nightly_2019_12_10_commit_45aa7a88 =
+ "0x608060405234801561001057600080fd5b5060405161026c38038061026c8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101d08061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820ec5a7ce04b1c2f97a3d3e61ae1b5cb06585e81c504542fd9668a8ead654da72764736f6c637829302e352e31342d6e696768746c792e323031392e31322e31302b636f6d6d69742e34356161376138380059"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_5_14_nightly_2019_12_10_commit_45aa7a88)
+ bytecode_construtor_arguments = "#{bytecode_0_5_14_nightly_2019_12_10_commit_45aa7a88}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_5,
+ "compiler_version" => "v0.5.14-nightly.2019.12.10+commit.45aa7a88",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verification is successful if proper nightly version of compiler ~0.6.0" do
+ bytecode_0_6_1_nightly_2020_1_2_commit_d082b9b8 =
+ "0x608060405234801561001057600080fd5b5060405161026a38038061026a8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101ce8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea264697066735822122029b5dde5889a195ed02cebb1a638ae3754be34464b9a2bc8b48b6286636031fb64736f6c637826302e362e312d6e696768746c792e323032302e312e322b636f6d6d69742e64303832623962380057"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_6_1_nightly_2020_1_2_commit_d082b9b8)
+ bytecode_construtor_arguments = "#{bytecode_0_6_1_nightly_2020_1_2_commit_d082b9b8}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_6,
+ "compiler_version" => "v0.6.1-nightly.2020.1.2+commit.d082b9b8",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ assert {:ok, %{abi: abi}} = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert abi != nil
+ end
+
+ test "verification is failed if wrong nightly version of compiler ~0.5.11" do
+ bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753 =
+ "0x608060405234801561001057600080fd5b5060405161026b38038061026b8339818101604052602081101561003357600080fd5b81019080805190602001909291905050508060008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506101cf8061009c6000396000f3fe608060405234801561001057600080fd5b506004361061005e576000357c010000000000000000000000000000000000000000000000000000000090048063256fec88146100635780633fa4f245146100ad578063812600df146100cb575b600080fd5b61006b6100f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100b561011f565b6040518082815260200191505060405180910390f35b6100f7600480360360208110156100e157600080fd5b8101908080359060200190929190505050610125565b005b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b806000540160008190555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72305820f7420b8c3b16d83ce728d8c279f0f887c4dcd7bfcd38c484acc9cdb82fde785764736f6c637828302e352e31312d6e696768746c792e323031392e362e32352b636f6d6d69742e31636338343735330058"
+
+ constructor_arguments = "000000000000000000000000000000000000000000000000000000000000000a"
+ contract_address = insert(:contract_address, contract_code: bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753)
+ bytecode_construtor_arguments = "#{bytecode_0_5_11_nightly_2019_6_25_commit_1cc84753}#{constructor_arguments}"
+
+ :transaction
+ |> insert(
+ created_contract_address_hash: contract_address.hash,
+ input: bytecode_construtor_arguments
+ )
+ |> with_block()
+
+ params = %{
+ "contract_source_code" => @code_0_5,
+ "compiler_version" => "v0.5.11-nightly.2019.8.10+commit.f5f2bbb2",
+ "evm_version" => "homestead",
+ "name" => "Incrementer",
+ "optimization" => false,
+ "constructor_arguments" => constructor_arguments
+ }
+
+ response = Verifier.evaluate_authenticity(contract_address.hash, params)
+ assert {:error, :compiler_version} = response
+ end
end
end
diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex
index 668d5fa6f6..fa932c1e1d 100644
--- a/apps/explorer/test/support/factory.ex
+++ b/apps/explorer/test/support/factory.ex
@@ -16,6 +16,7 @@ defmodule Explorer.Factory do
Address.CurrentTokenBalance,
Address.TokenBalance,
Address.CoinBalance,
+ Address.CoinBalanceDaily,
Block,
ContractMethod,
Data,
@@ -56,6 +57,13 @@ defmodule Explorer.Factory do
}
end
+ def unfetched_balance_daily_factory do
+ %CoinBalanceDaily{
+ address_hash: address_hash(),
+ day: Timex.shift(Timex.now(), days: Enum.random(0..100) * -1)
+ }
+ end
+
def update_balance_value(%CoinBalance{address_hash: address_hash, block_number: block_number}, value) do
Repo.update_all(
from(
@@ -71,6 +79,11 @@ defmodule Explorer.Factory do
|> struct!(value: Enum.random(1..100_000))
end
+ def fetched_balance_daily_factory do
+ unfetched_balance_daily_factory()
+ |> struct!(value: Enum.random(1..100_000))
+ end
+
def contract_address_factory do
%Address{
hash: address_hash(),
@@ -82,6 +95,8 @@ defmodule Explorer.Factory do
%{
bytecode:
"0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820f65a3adc1cfb055013d1dc37d0fe98676e2a5963677fa7541a10386d163446680029",
+ tx_input:
+ "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820853a985d0a4b20246785fc2f0357c202faa3db289980a48737180f358f9ddc3c0029",
name: "SimpleStorage",
source_code: """
pragma solidity ^0.4.24;
diff --git a/apps/explorer/test/support/fixture/smart_contract/compiler_tests.json b/apps/explorer/test/support/fixture/smart_contract/compiler_tests.json
index ee098b3d7f..2958c780be 100644
--- a/apps/explorer/test/support/fixture/smart_contract/compiler_tests.json
+++ b/apps/explorer/test/support/fixture/smart_contract/compiler_tests.json
@@ -3,6 +3,7 @@
"compiler_version": "v0.4.11+commit.68ef5810",
"contract": "pragma solidity ^0.4.11;\n/**\n * @title ERC20Basic\n * @dev Simpler version of ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/179\n */\ncontract ERC20Basic {\n uint256 public totalSupply;\n function balanceOf(address who) public constant returns (uint256);\n function transfer(address to, uint256 value) public returns (bool);\n event Transfer(address indexed from, address indexed to, uint256 value);\n}\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\ncontract Ownable {\n address public owner;\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n /**\n * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n * account.\n */\n function Ownable() {\n owner = msg.sender;\n }\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n /**\n * @dev Allows the current owner to transfer control of the contract to a newOwner.\n * @param newOwner The address to transfer ownership to.\n */\n function transferOwnership(address newOwner) onlyOwner public {\n require(newOwner != address(0));\n OwnershipTransferred(owner, newOwner);\n owner = newOwner;\n }\n}\n// Temporarily have SafeMath here until all contracts have been migrated to SafeMathLib version from OpenZeppelin\n/**\n * Math operations with safety checks\n */\ncontract SafeMath {\n function safeMul(uint a, uint b) internal returns (uint) {\n uint c = a * b;\n assert(a == 0 || c / a == b);\n return c;\n }\n function safeDiv(uint a, uint b) internal returns (uint) {\n assert(b > 0);\n uint c = a / b;\n assert(a == b * c + a % b);\n return c;\n }\n function safeSub(uint a, uint b) internal returns (uint) {\n assert(b <= a);\n return a - b;\n }\n function safeAdd(uint a, uint b) internal returns (uint) {\n uint c = a + b;\n assert(c>=a && c>=b);\n return c;\n }\n function max64(uint64 a, uint64 b) internal constant returns (uint64) {\n return a >= b ? a : b;\n }\n function min64(uint64 a, uint64 b) internal constant returns (uint64) {\n return a < b ? a : b;\n }\n function max256(uint256 a, uint256 b) internal constant returns (uint256) {\n return a >= b ? a : b;\n }\n function min256(uint256 a, uint256 b) internal constant returns (uint256) {\n return a < b ? a : b;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * @title ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/20\n */\ncontract ERC20 is ERC20Basic {\n function allowance(address owner, address spender) public constant returns (uint256);\n function transferFrom(address from, address to, uint256 value) public returns (bool);\n function approve(address spender, uint256 value) public returns (bool);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n/**\n * Standard ERC20 token with Short Hand Attack and approve() race condition mitigation.\n *\n * Based on code by FirstBlood:\n * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol\n */\ncontract StandardToken is ERC20, SafeMath {\n /* Token supply got increased and a new owner received these tokens */\n event Minted(address receiver, uint amount);\n /* Actual balances of token holders */\n mapping(address => uint) balances;\n /* approve() allowances */\n mapping (address => mapping (address => uint)) allowed;\n /* Interface declaration */\n function isToken() public constant returns (bool weAre) {\n return true;\n }\n function transfer(address _to, uint _value) returns (bool success) {\n balances[msg.sender] = safeSub(balances[msg.sender], _value);\n balances[_to] = safeAdd(balances[_to], _value);\n Transfer(msg.sender, _to, _value);\n return true;\n }\n function transferFrom(address _from, address _to, uint _value) returns (bool success) {\n uint _allowance = allowed[_from][msg.sender];\n balances[_to] = safeAdd(balances[_to], _value);\n balances[_from] = safeSub(balances[_from], _value);\n allowed[_from][msg.sender] = safeSub(_allowance, _value);\n Transfer(_from, _to, _value);\n return true;\n }\n function balanceOf(address _owner) constant returns (uint balance) {\n return balances[_owner];\n }\n function approve(address _spender, uint _value) returns (bool success) {\n // To change the approve amount you first have to reduce the addresses`\n // allowance to zero by calling `approve(_spender, 0)` if it is not\n // already 0 to mitigate the race condition described here:\n // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;\n allowed[msg.sender][_spender] = _value;\n Approval(msg.sender, _spender, _value);\n return true;\n }\n function allowance(address _owner, address _spender) constant returns (uint remaining) {\n return allowed[_owner][_spender];\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Upgrade agent interface inspired by Lunyr.\n *\n * Upgrade agent transfers tokens to a new contract.\n * Upgrade agent itself can be the token contract, or just a middle man contract doing the heavy lifting.\n */\ncontract UpgradeAgent {\n uint public originalSupply;\n /** Interface marker */\n function isUpgradeAgent() public constant returns (bool) {\n return true;\n }\n function upgradeFrom(address _from, uint256 _value) public;\n}\n/**\n * A token upgrade mechanism where users can opt-in amount of tokens to the next smart contract revision.\n *\n * First envisioned by Golem and Lunyr projects.\n */\ncontract UpgradeableToken is StandardToken {\n /** Contract / person who can set the upgrade path. This can be the same as team multisig wallet, as what it is with its default value. */\n address public upgradeMaster;\n /** The next contract where the tokens will be migrated. */\n UpgradeAgent public upgradeAgent;\n /** How many tokens we have upgraded by now. */\n uint256 public totalUpgraded;\n /**\n * Upgrade states.\n *\n * - NotAllowed: The child contract has not reached a condition where the upgrade can bgun\n * - WaitingForAgent: Token allows upgrade, but we don't have a new agent yet\n * - ReadyToUpgrade: The agent is set, but not a single token has been upgraded yet\n * - Upgrading: Upgrade agent is set and the balance holders can upgrade their tokens\n *\n */\n enum UpgradeState {Unknown, NotAllowed, WaitingForAgent, ReadyToUpgrade, Upgrading}\n /**\n * Somebody has upgraded some of his tokens.\n */\n event Upgrade(address indexed _from, address indexed _to, uint256 _value);\n /**\n * New upgrade agent available.\n */\n event UpgradeAgentSet(address agent);\n /**\n * Do not allow construction without upgrade master set.\n */\n function UpgradeableToken(address _upgradeMaster) {\n upgradeMaster = _upgradeMaster;\n }\n /**\n * Allow the token holder to upgrade some of their tokens to a new contract.\n */\n function upgrade(uint256 value) public {\n UpgradeState state = getUpgradeState();\n if(!(state == UpgradeState.ReadyToUpgrade || state == UpgradeState.Upgrading)) {\n // Called in a bad state\n throw;\n }\n // Validate input value.\n if (value == 0) throw;\n balances[msg.sender] = safeSub(balances[msg.sender], value);\n // Take tokens out from circulation\n totalSupply = safeSub(totalSupply, value);\n totalUpgraded = safeAdd(totalUpgraded, value);\n // Upgrade agent reissues the tokens\n upgradeAgent.upgradeFrom(msg.sender, value);\n Upgrade(msg.sender, upgradeAgent, value);\n }\n /**\n * Set an upgrade agent that handles\n */\n function setUpgradeAgent(address agent) external {\n if(!canUpgrade()) {\n // The token is not yet in a state that we could think upgrading\n throw;\n }\n if (agent == 0x0) throw;\n // Only a master can designate the next agent\n if (msg.sender != upgradeMaster) throw;\n // Upgrade has already begun for an agent\n if (getUpgradeState() == UpgradeState.Upgrading) throw;\n upgradeAgent = UpgradeAgent(agent);\n // Bad interface\n if(!upgradeAgent.isUpgradeAgent()) throw;\n // Make sure that token supplies match in source and target\n if (upgradeAgent.originalSupply() != totalSupply) throw;\n UpgradeAgentSet(upgradeAgent);\n }\n /**\n * Get the state of the token upgrade.\n */\n function getUpgradeState() public constant returns(UpgradeState) {\n if(!canUpgrade()) return UpgradeState.NotAllowed;\n else if(address(upgradeAgent) == 0x00) return UpgradeState.WaitingForAgent;\n else if(totalUpgraded == 0) return UpgradeState.ReadyToUpgrade;\n else return UpgradeState.Upgrading;\n }\n /**\n * Change the upgrade master.\n *\n * This allows us to set a new owner for the upgrade mechanism.\n */\n function setUpgradeMaster(address master) public {\n if (master == 0x0) throw;\n if (msg.sender != upgradeMaster) throw;\n upgradeMaster = master;\n }\n /**\n * Child contract can enable to provide the condition when the upgrade can begun.\n */\n function canUpgrade() public constant returns(bool) {\n return true;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Define interface for releasing the token transfer after a successful crowdsale.\n */\ncontract ReleasableToken is ERC20, Ownable {\n /* The finalizer contract that allows unlift the transfer limits on this token */\n address public releaseAgent;\n /** A crowdsale contract can release us to the wild if ICO success. If false we are are in transfer lock up period.*/\n bool public released = false;\n /** Map of agents that are allowed to transfer tokens regardless of the lock down period. These are crowdsale contracts and possible the team multisig itself. */\n mapping (address => bool) public transferAgents;\n /**\n * Limit token transfer until the crowdsale is over.\n *\n */\n modifier canTransfer(address _sender) {\n if(!released) {\n if(!transferAgents[_sender]) {\n throw;\n }\n }\n _;\n }\n /**\n * Set the contract that can call release and make the token transferable.\n *\n * Design choice. Allow reset the release agent to fix fat finger mistakes.\n */\n function setReleaseAgent(address addr) onlyOwner inReleaseState(false) public {\n // We don't do interface check here as we might want to a normal wallet address to act as a release agent\n releaseAgent = addr;\n }\n /**\n * Owner can allow a particular address (a crowdsale contract) to transfer tokens despite the lock up period.\n */\n function setTransferAgent(address addr, bool state) onlyOwner inReleaseState(false) public {\n transferAgents[addr] = state;\n }\n /**\n * One way function to release the tokens to the wild.\n *\n * Can be called only from the release agent that is the final ICO contract. It is only called if the crowdsale has been success (first milestone reached).\n */\n function releaseTokenTransfer() public onlyReleaseAgent {\n released = true;\n }\n /** The function can be called only before or after the tokens have been releasesd */\n modifier inReleaseState(bool releaseState) {\n if(releaseState != released) {\n throw;\n }\n _;\n }\n /** The function can be called only by a whitelisted release agent. */\n modifier onlyReleaseAgent() {\n if(msg.sender != releaseAgent) {\n throw;\n }\n _;\n }\n function transfer(address _to, uint _value) canTransfer(msg.sender) returns (bool success) {\n // Call StandardToken.transfer()\n return super.transfer(_to, _value);\n }\n function transferFrom(address _from, address _to, uint _value) canTransfer(_from) returns (bool success) {\n // Call StandardToken.transferForm()\n return super.transferFrom(_from, _to, _value);\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Safe unsigned safe math.\n *\n * https://blog.aragon.one/library-driven-development-in-solidity-2bebcaf88736#.750gwtwli\n *\n * Originally from https://raw.githubusercontent.com/AragonOne/zeppelin-solidity/master/contracts/SafeMathLib.sol\n *\n * Maintained here until merged to mainline zeppelin-solidity.\n *\n */\nlibrary SafeMathLibExt {\n function times(uint a, uint b) returns (uint) {\n uint c = a * b;\n assert(a == 0 || c / a == b);\n return c;\n }\n function divides(uint a, uint b) returns (uint) {\n assert(b > 0);\n uint c = a / b;\n assert(a == b * c + a % b);\n return c;\n }\n function minus(uint a, uint b) returns (uint) {\n assert(b <= a);\n return a - b;\n }\n function plus(uint a, uint b) returns (uint) {\n uint c = a + b;\n assert(c>=a);\n return c;\n }\n}\n/**\n * A token that can increase its supply by another contract.\n *\n * This allows uncapped crowdsale by dynamically increasing the supply when money pours in.\n * Only mint agents, contracts whitelisted by owner, can mint new tokens.\n *\n */\ncontract MintableTokenExt is StandardToken, Ownable {\n using SafeMathLibExt for uint;\n bool public mintingFinished = false;\n /** List of agents that are allowed to create new tokens */\n mapping (address => bool) public mintAgents;\n event MintingAgentChanged(address addr, bool state );\n struct ReservedTokensData {\n uint inTokens;\n uint inPercentage;\n }\n mapping (address => ReservedTokensData) public reservedTokensList;\n address[] public reservedTokensDestinations;\n uint public reservedTokensDestinationsLen = 0;\n function setReservedTokensList(address addr, uint inTokens, uint inPercentage) onlyOwner {\n reservedTokensDestinations.push(addr);\n reservedTokensDestinationsLen++;\n reservedTokensList[addr] = ReservedTokensData({inTokens:inTokens, inPercentage:inPercentage});\n }\n function getReservedTokensListValInTokens(address addr) constant returns (uint inTokens) {\n return reservedTokensList[addr].inTokens;\n }\n function getReservedTokensListValInPercentage(address addr) constant returns (uint inPercentage) {\n return reservedTokensList[addr].inPercentage;\n }\n function setReservedTokensListMultiple(address[] addrs, uint[] inTokens, uint[] inPercentage) onlyOwner {\n for (uint iterator = 0; iterator < addrs.length; iterator++) {\n setReservedTokensList(addrs[iterator], inTokens[iterator], inPercentage[iterator]);\n }\n }\n /**\n * Create new tokens and allocate them to an address..\n *\n * Only callably by a crowdsale contract (mint agent).\n */\n function mint(address receiver, uint amount) onlyMintAgent canMint public {\n totalSupply = totalSupply.plus(amount);\n balances[receiver] = balances[receiver].plus(amount);\n // This will make the mint transaction apper in EtherScan.io\n // We can remove this after there is a standardized minting event\n Transfer(0, receiver, amount);\n }\n /**\n * Owner can allow a crowdsale contract to mint new tokens.\n */\n function setMintAgent(address addr, bool state) onlyOwner canMint public {\n mintAgents[addr] = state;\n MintingAgentChanged(addr, state);\n }\n modifier onlyMintAgent() {\n // Only crowdsale contracts are allowed to mint new tokens\n if(!mintAgents[msg.sender]) {\n throw;\n }\n _;\n }\n /** Make sure we are not done yet. */\n modifier canMint() {\n if(mintingFinished) throw;\n _;\n }\n}\n/**\n * A crowdsaled token.\n *\n * An ERC-20 token designed specifically for crowdsales with investor protection and further development path.\n *\n * - The token transfer() is disabled until the crowdsale is over\n * - The token contract gives an opt-in upgrade path to a new contract\n * - The same token can be part of several crowdsales through approve() mechanism\n * - The token can be capped (supply set in the constructor) or uncapped (crowdsale contract can mint new tokens)\n *\n */\ncontract CrowdsaleTokenExt is ReleasableToken, MintableTokenExt, UpgradeableToken {\n /** Name and symbol were updated. */\n event UpdatedTokenInformation(string newName, string newSymbol);\n string public name;\n string public symbol;\n uint public decimals;\n /* Minimum ammount of tokens every buyer can buy. */\n uint public minCap;\n /**\n * Construct the token.\n *\n * This token must be created through a team multisig wallet, so that it is owned by that wallet.\n *\n * @param _name Token name\n * @param _symbol Token symbol - should be all caps\n * @param _initialSupply How many tokens we start with\n * @param _decimals Number of decimal places\n * @param _mintable Are new tokens created over the crowdsale or do we distribute only the initial supply? Note that when the token becomes transferable the minting always ends.\n */\n function CrowdsaleTokenExt(string _name, string _symbol, uint _initialSupply, uint _decimals, bool _mintable, uint _globalMinCap)\n UpgradeableToken(msg.sender) {\n // Create any address, can be transferred\n // to team multisig via changeOwner(),\n // also remember to call setUpgradeMaster()\n owner = msg.sender;\n name = _name;\n symbol = _symbol;\n totalSupply = _initialSupply;\n decimals = _decimals;\n minCap = _globalMinCap;\n // Create initially all balance on the team multisig\n balances[owner] = totalSupply;\n if(totalSupply > 0) {\n Minted(owner, totalSupply);\n }\n // No more new supply allowed after the token creation\n if(!_mintable) {\n mintingFinished = true;\n if(totalSupply == 0) {\n throw; // Cannot create a token without supply and no minting\n }\n }\n }\n /**\n * When token is released to be transferable, enforce no new tokens can be created.\n */\n function releaseTokenTransfer() public onlyReleaseAgent {\n mintingFinished = true;\n super.releaseTokenTransfer();\n }\n /**\n * Allow upgrade agent functionality kick in only if the crowdsale was success.\n */\n function canUpgrade() public constant returns(bool) {\n return released && super.canUpgrade();\n }\n /**\n * Owner can update token information here.\n *\n * It is often useful to conceal the actual token association, until\n * the token operations, like central issuance or reissuance have been completed.\n *\n * This function allows the token owner to rename the token after the operations\n * have been completed and then point the audience to use the token contract.\n */\n function setTokenInformation(string _name, string _symbol) onlyOwner {\n name = _name;\n symbol = _symbol;\n UpdatedTokenInformation(name, symbol);\n }\n}",
"expected_bytecode": "606060405236156101e05763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166302f652a381146101e257806305d2035b1461020557806306fdde0314610229578063095ea7b3146102b957806318160ddd146102ec57806323b872dd1461030e57806329ff4f5314610347578063313ce56714610365578063338f43a0146103875780633fa615b0146103b557806340c10f19146103d757806342c1867b146103f8578063432146751461042857806345977d031461044b5780634eee966f1461046057806351ed17a4146104f55780635de4ccb01461052a5780635f412d4f14610556578063600440cb1461056857806370a08231146105945780637386f0a7146105c257806380c190cf146105f15780638444b3911461061f578063867c2857146106535780638da5cb5b1461068357806395d89b41146106af578063961325211461073f5780639738968c14610763578063a9059cbb14610787578063b4ffaece146107ba578063c33105171461087f578063c752ff62146108a1578063d1f276d3146108c3578063d7e7088a146108ef578063dd62ed3e1461090d578063eefa597b14610941578063f2fde38b14610965578063f30f850814610983578063ffeb7d75146109a7575bfe5b34156101ea57fe5b610203600160a060020a036004351660243515156109c5565b005b341561020d57fe5b610215610a28565b604080519115158252519081900360200190f35b341561023157fe5b610239610a31565b60408051602080825283518183015283519192839290830191850190808383821561027f575b80518252602083111561027f57601f19909201916020918201910161025f565b505050905090810190601f1680156102ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102c157fe5b610215600160a060020a0360043516602435610abf565b604080519115158252519081900360200190f35b34156102f457fe5b6102fc610b66565b60408051918252519081900360200190f35b341561031657fe5b610215600160a060020a0360043581169060243516604435610b6c565b604080519115158252519081900360200190f35b341561034f57fe5b610203600160a060020a0360043516610bc4565b005b341561036d57fe5b6102fc610c2a565b60408051918252519081900360200190f35b341561038f57fe5b6102fc600160a060020a0360043516610c30565b60408051918252519081900360200190f35b34156103bd57fe5b6102fc610c4f565b60408051918252519081900360200190f35b34156103df57fe5b610203600160a060020a0360043516602435610c55565b005b341561040057fe5b610215600160a060020a0360043516610e1b565b604080519115158252519081900360200190f35b341561043057fe5b610203600160a060020a03600435166024351515610e30565b005b341561045357fe5b610203600435610ec4565b005b341561046857fe5b610203600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f89358b0180359182018390048302840183019094528083529799988101979196509182019450925082915084018382808284375094965061103495505050505050565b005b34156104fd57fe5b610511600160a060020a03600435166111a8565b6040805192835260208301919091528051918290030190f35b341561053257fe5b61053a6111c1565b60408051600160a060020a039092168252519081900360200190f35b341561055e57fe5b6102036111d0565b005b341561057057fe5b61053a611205565b60408051600160a060020a039092168252519081900360200190f35b341561059c57fe5b6102fc600160a060020a0360043516611214565b60408051918252519081900360200190f35b34156105ca57fe5b61053a600435611233565b60408051600160a060020a039092168252519081900360200190f35b34156105f957fe5b6102fc600160a060020a0360043516611265565b60408051918252519081900360200190f35b341561062757fe5b61062f611287565b6040518082600481111561063f57fe5b60ff16815260200191505060405180910390f35b341561065b57fe5b610215600160a060020a03600435166112d4565b604080519115158252519081900360200190f35b341561068b57fe5b61053a6112e9565b60408051600160a060020a039092168252519081900360200190f35b34156106b757fe5b6102396112f8565b60408051602080825283518183015283519192839290830191850190808383821561027f575b80518252602083111561027f57601f19909201916020918201910161025f565b505050905090810190601f1680156102ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561074757fe5b610215611386565b604080519115158252519081900360200190f35b341561076b57fe5b610215611396565b604080519115158252519081900360200190f35b341561078f57fe5b610215600160a060020a03600435166024356113bc565b604080519115158252519081900360200190f35b34156107c257fe5b610203600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a99890198929750908201955093508392508501908490808284375094965061141295505050505050565b005b341561088757fe5b6102fc61149f565b60408051918252519081900360200190f35b34156108a957fe5b6102fc6114a5565b60408051918252519081900360200190f35b34156108cb57fe5b61053a6114ab565b60408051600160a060020a039092168252519081900360200190f35b34156108f757fe5b610203600160a060020a03600435166114ba565b005b341561091557fe5b6102fc600160a060020a0360043581169060243516611697565b60408051918252519081900360200190f35b341561094957fe5b6102156116c4565b604080519115158252519081900360200190f35b341561096d57fe5b610203600160a060020a03600435166116ca565b005b341561098b57fe5b610203600160a060020a0360043516602435604435611763565b005b34156109af57fe5b610203600160a060020a03600435166117fe565b005b60035433600160a060020a039081169116146109e15760006000fd5b60045460009060a060020a900460ff16156109fc5760006000fd5b600160a060020a0383166000908152600560205260409020805460ff19168315151790555b5b505b5050565b60065460ff1681565b600e805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ab75780601f10610a8c57610100808354040283529160200191610ab7565b820191906000526020600020905b815481529060010190602001808311610a9a57829003601f168201915b505050505081565b60008115801590610af45750600160a060020a0333811660009081526002602090815260408083209387168352929052205415155b15610aff5760006000fd5b600160a060020a03338116600081815260026020908152604080832094881680845294825291829020869055815186815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35060015b92915050565b60005481565b600454600090849060a060020a900460ff161515610bac57600160a060020a03811660009081526005602052604090205460ff161515610bac5760006000fd5b5b610bb885858561185c565b91505b5b509392505050565b60035433600160a060020a03908116911614610be05760006000fd5b60045460009060a060020a900460ff1615610bfb5760006000fd5b6004805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5b505b50565b60105481565b600160a060020a0381166000908152600860205260409020545b919050565b60115481565b600160a060020a03331660009081526007602052604090205460ff161515610c7d5760006000fd5b60065460ff1615610c8e5760006000fd5b6000547354ca5a7c536dbed5897b78d30a93dcd0e46fbdac6366098d4f9091836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b1515610d0a57fe5b6102c65a03f41515610d1857fe5b50506040805180516000908155600160a060020a038616815260016020908152838220549281019190915282517f66098d4f00000000000000000000000000000000000000000000000000000000815260048101929092526024820185905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b1515610daf57fe5b6102c65a03f41515610dbd57fe5b5050604080518051600160a060020a0386166000818152600160209081528582209390935586845293519094507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35b5b5b5050565b60076020526000908152604090205460ff1681565b60035433600160a060020a03908116911614610e4c5760006000fd5b60065460ff1615610e5d5760006000fd5b600160a060020a038216600081815260076020908152604091829020805460ff191685151590811790915582519384529083015280517f4b0adf6c802794c7dde28a08a4e07131abcff3bf9603cd71f14f90bec7865efa9281900390910190a15b5b5b5050565b6000610ece611287565b905060035b816004811115610edf57fe5b1480610ef7575060045b816004811115610ef557fe5b145b1515610f035760006000fd5b811515610f105760006000fd5b600160a060020a033316600090815260016020526040902054610f33908361195f565b600160a060020a03331660009081526001602052604081209190915554610f5a908361195f565b600055600d54610f6a9083611976565b600d55600c54604080517f753e88e5000000000000000000000000000000000000000000000000000000008152600160a060020a033381166004830152602482018690529151919092169163753e88e591604480830192600092919082900301818387803b1515610fd757fe5b6102c65a03f11515610fe557fe5b5050600c54604080518581529051600160a060020a03928316935033909216917f7e5c344a8141a805725cb476f76c6953b842222b967edd1f78ddb6e8b3f397ac9181900360200190a35b5050565b60035433600160a060020a039081169116146110505760006000fd5b815161106390600e906020850190611a9c565b50805161107790600f906020840190611a9c565b5060408051818152600e8054600260001961010060018416150201909116049282018390527fd131ab1e6f279deea74e13a18477e13e2107deb6dc8ae955648948be5841fb46929091600f918190602082019060608301908690801561111e5780601f106110f35761010080835404028352916020019161111e565b820191906000526020600020905b81548152906001019060200180831161110157829003601f168201915b50508381038252845460026000196101006001841615020190911604808252602090910190859080156111925780601f1061116757610100808354040283529160200191611192565b820191906000526020600020905b81548152906001019060200180831161117557829003601f168201915b505094505050505060405180910390a15b5b5050565b6008602052600090815260409020805460019091015482565b600c54600160a060020a031681565b60045433600160a060020a039081169116146111ec5760006000fd5b6006805460ff1916600117905561120161199e565b5b5b565b600b54600160a060020a031681565b600160a060020a0381166000908152600160205260409020545b919050565b600980548290811061124157fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600160a060020a0381166000908152600860205260409020600101545b919050565b6000611291611396565b151561129f575060016112ce565b600c54600160a060020a031615156112b9575060026112ce565b600d5415156112ca575060036112ce565b5060045b5b5b5b90565b60056020526000908152604090205460ff1681565b600354600160a060020a031681565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ab75780601f10610a8c57610100808354040283529160200191610ab7565b820191906000526020600020905b815481529060010190602001808311610a9a57829003601f168201915b505050505081565b60045460a060020a900460ff1681565b60045460009060a060020a900460ff1680156113b557506113b56116c4565b5b90505b90565b600454600090339060a060020a900460ff1615156113fc57600160a060020a03811660009081526005602052604090205460ff1615156113fc5760006000fd5b5b61140784846119e8565b91505b5b5092915050565b60035460009033600160a060020a039081169116146114315760006000fd5b5060005b83518110156114975761148e848281518110151561144f57fe5b90602001906020020151848381518110151561146757fe5b90602001906020020151848481518110151561147f57fe5b90602001906020020151611763565b5b600101611435565b5b5b50505050565b600a5481565b600d5481565b600454600160a060020a031681565b6114c2611396565b15156114ce5760006000fd5b600160a060020a03811615156114e45760006000fd5b600b5433600160a060020a039081169116146115005760006000fd5b60045b61150b611287565b600481111561151657fe5b14156115225760006000fd5b600c805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038381169190911791829055604080516000602091820181905282517f61d3d7a6000000000000000000000000000000000000000000000000000000008152925194909316936361d3d7a6936004808501948390030190829087803b15156115a857fe5b6102c65a03f115156115b657fe5b505060405151151590506115ca5760006000fd5b60008054600c5460408051602090810185905281517f4b2ba0dd00000000000000000000000000000000000000000000000000000000815291519394600160a060020a0390931693634b2ba0dd936004808501948390030190829087803b151561163057fe5b6102c65a03f1151561163e57fe5b5050604051519190911490506116545760006000fd5b600c5460408051600160a060020a039092168252517f7845d5aa74cc410e35571258d954f23b82276e160fe8c188fa80566580f279cc9181900360200190a15b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b60015b90565b60035433600160a060020a039081169116146116e65760006000fd5b600160a060020a03811615156116fc5760006000fd5b600354604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b60035433600160a060020a0390811691161461177f5760006000fd5b60098054600181016117918382611b1b565b916000526020600020900160005b8154600160a060020a038088166101009390930a83810291021990911617909155600a80546001908101909155604080518082018252868152602080820187815260009586526008909152919093209251835551910155505b5b505050565b600160a060020a03811615156118145760006000fd5b600b5433600160a060020a039081169116146118305760006000fd5b600b805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b50565b600160a060020a03808416600090815260026020908152604080832033851684528252808320549386168352600190915281205490919061189d9084611976565b600160a060020a0380861660009081526001602052604080822093909355908716815220546118cc908461195f565b600160a060020a0386166000908152600160205260409020556118ef818461195f565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60008282111561196b57fe5b508082035b92915050565b600082820183811080159061198b5750828110155b151561199357fe5b8091505b5092915050565b60045433600160a060020a039081169116146119ba5760006000fd5b6004805474ff0000000000000000000000000000000000000000191660a060020a1790555b5b565b60015b90565b600160a060020a033316600090815260016020526040812054611a0b908361195f565b600160a060020a033381166000908152600160205260408082209390935590851681522054611a3a9083611976565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611add57805160ff1916838001178555611b0a565b82800160010185558215611b0a579182015b82811115611b0a578251825591602001919060010190611aef565b5b50611b17929150611b45565b5090565b815481835581811511610a2157600083815260209020610a21918101908301611b45565b5b505050565b6112ce91905b80821115611b175760008155600101611b4b565b5090565b905600a165627a7a72305820c38ce552da1339b41e837cc46418755767ab24eb6b08726516f1e03f7b96fca9002900000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000085570666972696e6700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035546520000000000000000000000000000000000000000000000000000000000",
+ "tx_input": "60606040526004805460a060020a60ff02191690556006805460ff191690556000600a5534156200002c57fe5b60405162001deb38038062001deb83398101604090815281516020830151918301516060840151608085015160a086015193860195949094019391929091905b335b5b60038054600160a060020a03191633600160a060020a03161790555b600b8054600160a060020a031916600160a060020a0383161790555b5060038054600160a060020a03191633600160a060020a03161790558551620000d890600e9060208901906200019f565b508451620000ee90600f9060208801906200019f565b50600084815560108490556011829055600354600160a060020a031681526001602052604081208590558411156200016c5760035460005460408051600160a060020a039093168352602083019190915280517f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe9281900390910190a15b81151562000191576006805460ff191660011790556000541515620001915760006000fd5b5b5b50505050505062000249565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620001e257805160ff191683800117855562000212565b8280016001018555821562000212579182015b8281111562000212578251825591602001919060010190620001f5565b5b506200022192915062000225565b5090565b6200024691905b808211156200022157600081556001016200022c565b5090565b90565b611b9280620002596000396000f300606060405236156101e05763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166302f652a381146101e257806305d2035b1461020557806306fdde0314610229578063095ea7b3146102b957806318160ddd146102ec57806323b872dd1461030e57806329ff4f5314610347578063313ce56714610365578063338f43a0146103875780633fa615b0146103b557806340c10f19146103d757806342c1867b146103f8578063432146751461042857806345977d031461044b5780634eee966f1461046057806351ed17a4146104f55780635de4ccb01461052a5780635f412d4f14610556578063600440cb1461056857806370a08231146105945780637386f0a7146105c257806380c190cf146105f15780638444b3911461061f578063867c2857146106535780638da5cb5b1461068357806395d89b41146106af578063961325211461073f5780639738968c14610763578063a9059cbb14610787578063b4ffaece146107ba578063c33105171461087f578063c752ff62146108a1578063d1f276d3146108c3578063d7e7088a146108ef578063dd62ed3e1461090d578063eefa597b14610941578063f2fde38b14610965578063f30f850814610983578063ffeb7d75146109a7575bfe5b34156101ea57fe5b610203600160a060020a036004351660243515156109c5565b005b341561020d57fe5b610215610a28565b604080519115158252519081900360200190f35b341561023157fe5b610239610a31565b60408051602080825283518183015283519192839290830191850190808383821561027f575b80518252602083111561027f57601f19909201916020918201910161025f565b505050905090810190601f1680156102ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34156102c157fe5b610215600160a060020a0360043516602435610abf565b604080519115158252519081900360200190f35b34156102f457fe5b6102fc610b66565b60408051918252519081900360200190f35b341561031657fe5b610215600160a060020a0360043581169060243516604435610b6c565b604080519115158252519081900360200190f35b341561034f57fe5b610203600160a060020a0360043516610bc4565b005b341561036d57fe5b6102fc610c2a565b60408051918252519081900360200190f35b341561038f57fe5b6102fc600160a060020a0360043516610c30565b60408051918252519081900360200190f35b34156103bd57fe5b6102fc610c4f565b60408051918252519081900360200190f35b34156103df57fe5b610203600160a060020a0360043516602435610c55565b005b341561040057fe5b610215600160a060020a0360043516610e1b565b604080519115158252519081900360200190f35b341561043057fe5b610203600160a060020a03600435166024351515610e30565b005b341561045357fe5b610203600435610ec4565b005b341561046857fe5b610203600480803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284375050604080516020601f89358b0180359182018390048302840183019094528083529799988101979196509182019450925082915084018382808284375094965061103495505050505050565b005b34156104fd57fe5b610511600160a060020a03600435166111a8565b6040805192835260208301919091528051918290030190f35b341561053257fe5b61053a6111c1565b60408051600160a060020a039092168252519081900360200190f35b341561055e57fe5b6102036111d0565b005b341561057057fe5b61053a611205565b60408051600160a060020a039092168252519081900360200190f35b341561059c57fe5b6102fc600160a060020a0360043516611214565b60408051918252519081900360200190f35b34156105ca57fe5b61053a600435611233565b60408051600160a060020a039092168252519081900360200190f35b34156105f957fe5b6102fc600160a060020a0360043516611265565b60408051918252519081900360200190f35b341561062757fe5b61062f611287565b6040518082600481111561063f57fe5b60ff16815260200191505060405180910390f35b341561065b57fe5b610215600160a060020a03600435166112d4565b604080519115158252519081900360200190f35b341561068b57fe5b61053a6112e9565b60408051600160a060020a039092168252519081900360200190f35b34156106b757fe5b6102396112f8565b60408051602080825283518183015283519192839290830191850190808383821561027f575b80518252602083111561027f57601f19909201916020918201910161025f565b505050905090810190601f1680156102ab5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561074757fe5b610215611386565b604080519115158252519081900360200190f35b341561076b57fe5b610215611396565b604080519115158252519081900360200190f35b341561078f57fe5b610215600160a060020a03600435166024356113bc565b604080519115158252519081900360200190f35b34156107c257fe5b610203600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a99890198929750908201955093508392508501908490808284375094965061141295505050505050565b005b341561088757fe5b6102fc61149f565b60408051918252519081900360200190f35b34156108a957fe5b6102fc6114a5565b60408051918252519081900360200190f35b34156108cb57fe5b61053a6114ab565b60408051600160a060020a039092168252519081900360200190f35b34156108f757fe5b610203600160a060020a03600435166114ba565b005b341561091557fe5b6102fc600160a060020a0360043581169060243516611697565b60408051918252519081900360200190f35b341561094957fe5b6102156116c4565b604080519115158252519081900360200190f35b341561096d57fe5b610203600160a060020a03600435166116ca565b005b341561098b57fe5b610203600160a060020a0360043516602435604435611763565b005b34156109af57fe5b610203600160a060020a03600435166117fe565b005b60035433600160a060020a039081169116146109e15760006000fd5b60045460009060a060020a900460ff16156109fc5760006000fd5b600160a060020a0383166000908152600560205260409020805460ff19168315151790555b5b505b5050565b60065460ff1681565b600e805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ab75780601f10610a8c57610100808354040283529160200191610ab7565b820191906000526020600020905b815481529060010190602001808311610a9a57829003601f168201915b505050505081565b60008115801590610af45750600160a060020a0333811660009081526002602090815260408083209387168352929052205415155b15610aff5760006000fd5b600160a060020a03338116600081815260026020908152604080832094881680845294825291829020869055815186815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35060015b92915050565b60005481565b600454600090849060a060020a900460ff161515610bac57600160a060020a03811660009081526005602052604090205460ff161515610bac5760006000fd5b5b610bb885858561185c565b91505b5b509392505050565b60035433600160a060020a03908116911614610be05760006000fd5b60045460009060a060020a900460ff1615610bfb5760006000fd5b6004805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5b505b50565b60105481565b600160a060020a0381166000908152600860205260409020545b919050565b60115481565b600160a060020a03331660009081526007602052604090205460ff161515610c7d5760006000fd5b60065460ff1615610c8e5760006000fd5b6000547354ca5a7c536dbed5897b78d30a93dcd0e46fbdac6366098d4f9091836000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b1515610d0a57fe5b6102c65a03f41515610d1857fe5b50506040805180516000908155600160a060020a038616815260016020908152838220549281019190915282517f66098d4f00000000000000000000000000000000000000000000000000000000815260048101929092526024820185905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b1515610daf57fe5b6102c65a03f41515610dbd57fe5b5050604080518051600160a060020a0386166000818152600160209081528582209390935586845293519094507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35b5b5b5050565b60076020526000908152604090205460ff1681565b60035433600160a060020a03908116911614610e4c5760006000fd5b60065460ff1615610e5d5760006000fd5b600160a060020a038216600081815260076020908152604091829020805460ff191685151590811790915582519384529083015280517f4b0adf6c802794c7dde28a08a4e07131abcff3bf9603cd71f14f90bec7865efa9281900390910190a15b5b5b5050565b6000610ece611287565b905060035b816004811115610edf57fe5b1480610ef7575060045b816004811115610ef557fe5b145b1515610f035760006000fd5b811515610f105760006000fd5b600160a060020a033316600090815260016020526040902054610f33908361195f565b600160a060020a03331660009081526001602052604081209190915554610f5a908361195f565b600055600d54610f6a9083611976565b600d55600c54604080517f753e88e5000000000000000000000000000000000000000000000000000000008152600160a060020a033381166004830152602482018690529151919092169163753e88e591604480830192600092919082900301818387803b1515610fd757fe5b6102c65a03f11515610fe557fe5b5050600c54604080518581529051600160a060020a03928316935033909216917f7e5c344a8141a805725cb476f76c6953b842222b967edd1f78ddb6e8b3f397ac9181900360200190a35b5050565b60035433600160a060020a039081169116146110505760006000fd5b815161106390600e906020850190611a9c565b50805161107790600f906020840190611a9c565b5060408051818152600e8054600260001961010060018416150201909116049282018390527fd131ab1e6f279deea74e13a18477e13e2107deb6dc8ae955648948be5841fb46929091600f918190602082019060608301908690801561111e5780601f106110f35761010080835404028352916020019161111e565b820191906000526020600020905b81548152906001019060200180831161110157829003601f168201915b50508381038252845460026000196101006001841615020190911604808252602090910190859080156111925780601f1061116757610100808354040283529160200191611192565b820191906000526020600020905b81548152906001019060200180831161117557829003601f168201915b505094505050505060405180910390a15b5b5050565b6008602052600090815260409020805460019091015482565b600c54600160a060020a031681565b60045433600160a060020a039081169116146111ec5760006000fd5b6006805460ff1916600117905561120161199e565b5b5b565b600b54600160a060020a031681565b600160a060020a0381166000908152600160205260409020545b919050565b600980548290811061124157fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b600160a060020a0381166000908152600860205260409020600101545b919050565b6000611291611396565b151561129f575060016112ce565b600c54600160a060020a031615156112b9575060026112ce565b600d5415156112ca575060036112ce565b5060045b5b5b5b90565b60056020526000908152604090205460ff1681565b600354600160a060020a031681565b600f805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ab75780601f10610a8c57610100808354040283529160200191610ab7565b820191906000526020600020905b815481529060010190602001808311610a9a57829003601f168201915b505050505081565b60045460a060020a900460ff1681565b60045460009060a060020a900460ff1680156113b557506113b56116c4565b5b90505b90565b600454600090339060a060020a900460ff1615156113fc57600160a060020a03811660009081526005602052604090205460ff1615156113fc5760006000fd5b5b61140784846119e8565b91505b5b5092915050565b60035460009033600160a060020a039081169116146114315760006000fd5b5060005b83518110156114975761148e848281518110151561144f57fe5b90602001906020020151848381518110151561146757fe5b90602001906020020151848481518110151561147f57fe5b90602001906020020151611763565b5b600101611435565b5b5b50505050565b600a5481565b600d5481565b600454600160a060020a031681565b6114c2611396565b15156114ce5760006000fd5b600160a060020a03811615156114e45760006000fd5b600b5433600160a060020a039081169116146115005760006000fd5b60045b61150b611287565b600481111561151657fe5b14156115225760006000fd5b600c805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038381169190911791829055604080516000602091820181905282517f61d3d7a6000000000000000000000000000000000000000000000000000000008152925194909316936361d3d7a6936004808501948390030190829087803b15156115a857fe5b6102c65a03f115156115b657fe5b505060405151151590506115ca5760006000fd5b60008054600c5460408051602090810185905281517f4b2ba0dd00000000000000000000000000000000000000000000000000000000815291519394600160a060020a0390931693634b2ba0dd936004808501948390030190829087803b151561163057fe5b6102c65a03f1151561163e57fe5b5050604051519190911490506116545760006000fd5b600c5460408051600160a060020a039092168252517f7845d5aa74cc410e35571258d954f23b82276e160fe8c188fa80566580f279cc9181900360200190a15b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b60015b90565b60035433600160a060020a039081169116146116e65760006000fd5b600160a060020a03811615156116fc5760006000fd5b600354604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b5b50565b60035433600160a060020a0390811691161461177f5760006000fd5b60098054600181016117918382611b1b565b916000526020600020900160005b8154600160a060020a038088166101009390930a83810291021990911617909155600a80546001908101909155604080518082018252868152602080820187815260009586526008909152919093209251835551910155505b5b505050565b600160a060020a03811615156118145760006000fd5b600b5433600160a060020a039081169116146118305760006000fd5b600b805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161790555b50565b600160a060020a03808416600090815260026020908152604080832033851684528252808320549386168352600190915281205490919061189d9084611976565b600160a060020a0380861660009081526001602052604080822093909355908716815220546118cc908461195f565b600160a060020a0386166000908152600160205260409020556118ef818461195f565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60008282111561196b57fe5b508082035b92915050565b600082820183811080159061198b5750828110155b151561199357fe5b8091505b5092915050565b60045433600160a060020a039081169116146119ba5760006000fd5b6004805474ff0000000000000000000000000000000000000000191660a060020a1790555b5b565b60015b90565b600160a060020a033316600090815260016020526040812054611a0b908361195f565b600160a060020a033381166000908152600160205260408082209390935590851681522054611a3a9083611976565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b92915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611add57805160ff1916838001178555611b0a565b82800160010185558215611b0a579182015b82811115611b0a578251825591602001919060010190611aef565b5b50611b17929150611b45565b5090565b815481835581811511610a2157600083815260209020610a21918101908301611b45565b5b505050565b6112ce91905b80821115611b175760008155600101611b4b565b5090565b905600a165627a7a723058203028bb284b175e68028f82d996d747776a424d31a87d8b1c56c23a83afe1bc8e002900000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000",
"external_libraries": {
"SafeMathLibExt": "0x54ca5a7c536dbed5897b78d30a93dcd0e46fbdac"
},
@@ -13,6 +14,7 @@
"compiler_version": "v0.4.11+commit.68ef5810",
"contract": "// Temporarily have SafeMath here until all contracts have been migrated to SafeMathLib version from OpenZeppelin\npragma solidity ^0.4.8;\n/**\n * Math operations with safety checks\n */\ncontract SafeMath {\n function safeMul(uint a, uint b) internal returns (uint) {\n uint c = a * b;\n assert(a == 0 || c / a == b);\n return c;\n }\n function safeDiv(uint a, uint b) internal returns (uint) {\n assert(b > 0);\n uint c = a / b;\n assert(a == b * c + a % b);\n return c;\n }\n function safeSub(uint a, uint b) internal returns (uint) {\n assert(b <= a);\n return a - b;\n }\n function safeAdd(uint a, uint b) internal returns (uint) {\n uint c = a + b;\n assert(c>=a && c>=b);\n return c;\n }\n function max64(uint64 a, uint64 b) internal constant returns (uint64) {\n return a >= b ? a : b;\n }\n function min64(uint64 a, uint64 b) internal constant returns (uint64) {\n return a < b ? a : b;\n }\n function max256(uint256 a, uint256 b) internal constant returns (uint256) {\n return a >= b ? a : b;\n }\n function min256(uint256 a, uint256 b) internal constant returns (uint256) {\n return a < b ? a : b;\n }\n}\n/**\n * @title ERC20Basic\n * @dev Simpler version of ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/179\n */\ncontract ERC20Basic {\n uint256 public totalSupply;\n function balanceOf(address who) public constant returns (uint256);\n function transfer(address to, uint256 value) public returns (bool);\n event Transfer(address indexed from, address indexed to, uint256 value);\n}\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\ncontract Ownable {\n address public owner;\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n /**\n * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n * account.\n */\n function Ownable() {\n owner = msg.sender;\n }\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(msg.sender == owner);\n _;\n }\n /**\n * @dev Allows the current owner to transfer control of the contract to a newOwner.\n * @param newOwner The address to transfer ownership to.\n */\n function transferOwnership(address newOwner) onlyOwner public {\n require(newOwner != address(0));\n OwnershipTransferred(owner, newOwner);\n owner = newOwner;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Safe unsigned safe math.\n *\n * https://blog.aragon.one/library-driven-development-in-solidity-2bebcaf88736#.750gwtwli\n *\n * Originally from https://raw.githubusercontent.com/AragonOne/zeppelin-solidity/master/contracts/SafeMathLib.sol\n *\n * Maintained here until merged to mainline zeppelin-solidity.\n *\n */\nlibrary SafeMathLibExt {\n function times(uint a, uint b) returns (uint) {\n uint c = a * b;\n assert(a == 0 || c / a == b);\n return c;\n }\n function divides(uint a, uint b) returns (uint) {\n assert(b > 0);\n uint c = a / b;\n assert(a == b * c + a % b);\n return c;\n }\n function minus(uint a, uint b) returns (uint) {\n assert(b <= a);\n return a - b;\n }\n function plus(uint a, uint b) returns (uint) {\n uint c = a + b;\n assert(c>=a);\n return c;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/*\n * Haltable\n *\n * Abstract contract that allows children to implement an\n * emergency stop mechanism. Differs from Pausable by causing a throw when in halt mode.\n *\n *\n * Originally envisioned in FirstBlood ICO contract.\n */\ncontract Haltable is Ownable {\n bool public halted;\n modifier stopInEmergency {\n if (halted) throw;\n _;\n }\n modifier stopNonOwnersInEmergency {\n if (halted && msg.sender != owner) throw;\n _;\n }\n modifier onlyInEmergency {\n if (!halted) throw;\n _;\n }\n // called by the owner on emergency, triggers stopped state\n function halt() external onlyOwner {\n halted = true;\n }\n // called by the owner on end of emergency, returns to normal state\n function unhalt() external onlyOwner onlyInEmergency {\n halted = false;\n }\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Interface for defining crowdsale pricing.\n */\ncontract PricingStrategy {\n /** Interface declaration. */\n function isPricingStrategy() public constant returns (bool) {\n return true;\n }\n /** Self check if all references are correctly set.\n *\n * Checks that pricing strategy matches crowdsale parameters.\n */\n function isSane(address crowdsale) public constant returns (bool) {\n return true;\n }\n /**\n * @dev Pricing tells if this is a presale purchase or not.\n @param purchaser Address of the purchaser\n @return False by default, true if a presale purchaser\n */\n function isPresalePurchase(address purchaser) public constant returns (bool) {\n return false;\n }\n /**\n * When somebody tries to buy tokens for X eth, calculate how many tokens they get.\n *\n *\n * @param value - What is the value of the transaction send in as wei\n * @param tokensSold - how much tokens have been sold this far\n * @param weiRaised - how much money has been raised this far in the main token sale - this number excludes presale\n * @param msgSender - who is the investor of this transaction\n * @param decimals - how many decimal units the token has\n * @return Amount of tokens the investor receives\n */\n function calculatePrice(uint value, uint weiRaised, uint tokensSold, address msgSender, uint decimals) public constant returns (uint tokenAmount);\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Finalize agent defines what happens at the end of succeseful crowdsale.\n *\n * - Allocate tokens for founders, bounties and community\n * - Make tokens transferable\n * - etc.\n */\ncontract FinalizeAgent {\n function isFinalizeAgent() public constant returns(bool) {\n return true;\n }\n /** Return true if we can run finalizeCrowdsale() properly.\n *\n * This is a safety check function that doesn't allow crowdsale to begin\n * unless the finalizer has been set up properly.\n */\n function isSane() public constant returns (bool);\n /** Called once by crowdsale finalize() if the sale was success. */\n function finalizeCrowdsale();\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * @title ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/20\n */\ncontract ERC20 is ERC20Basic {\n function allowance(address owner, address spender) public constant returns (uint256);\n function transferFrom(address from, address to, uint256 value) public returns (bool);\n function approve(address spender, uint256 value) public returns (bool);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n/**\n * A token that defines fractional units as decimals.\n */\ncontract FractionalERC20Ext is ERC20 {\n uint public decimals;\n uint public minCap;\n}\n/**\n * Abstract base contract for token sales.\n *\n * Handle\n * - start and end dates\n * - accepting investments\n * - minimum funding goal and refund\n * - various statistics during the crowdfund\n * - different pricing strategies\n * - different investment policies (require server side customer id, allow only whitelisted addresses)\n *\n */\ncontract CrowdsaleExt is Haltable {\n /* Max investment count when we are still allowed to change the multisig address */\n uint public MAX_INVESTMENTS_BEFORE_MULTISIG_CHANGE = 5;\n using SafeMathLibExt for uint;\n /* The token we are selling */\n FractionalERC20Ext public token;\n /* How we are going to price our offering */\n PricingStrategy public pricingStrategy;\n /* Post-success callback */\n FinalizeAgent public finalizeAgent;\n /* tokens will be transfered from this address */\n address public multisigWallet;\n /* if the funding goal is not reached, investors may withdraw their funds */\n uint public minimumFundingGoal;\n /* the UNIX timestamp start date of the crowdsale */\n uint public startsAt;\n /* the UNIX timestamp end date of the crowdsale */\n uint public endsAt;\n /* the number of tokens already sold through this contract*/\n uint public tokensSold = 0;\n /* How many wei of funding we have raised */\n uint public weiRaised = 0;\n /* Calculate incoming funds from presale contracts and addresses */\n uint public presaleWeiRaised = 0;\n /* How many distinct addresses have invested */\n uint public investorCount = 0;\n /* How much wei we have returned back to the contract after a failed crowdfund. */\n uint public loadedRefund = 0;\n /* How much wei we have given back to investors.*/\n uint public weiRefunded = 0;\n /* Has this crowdsale been finalized */\n bool public finalized;\n /* Do we need to have unique contributor id for each customer */\n bool public requireCustomerId;\n bool public isWhiteListed;\n address[] public joinedCrowdsales;\n uint public joinedCrowdsalesLen = 0;\n address public lastCrowdsale;\n /**\n * Do we verify that contributor has been cleared on the server side (accredited investors only).\n * This method was first used in FirstBlood crowdsale to ensure all contributors have accepted terms on sale (on the web).\n */\n bool public requiredSignedAddress;\n /* Server side address that signed allowed contributors (Ethereum addresses) that can participate the crowdsale */\n address public signerAddress;\n /** How much ETH each address has invested to this crowdsale */\n mapping (address => uint256) public investedAmountOf;\n /** How much tokens this crowdsale has credited for each investor address */\n mapping (address => uint256) public tokenAmountOf;\n struct WhiteListData {\n bool status;\n uint minCap;\n uint maxCap;\n }\n //is crowdsale updatable\n bool public isUpdatable;\n /** Addresses that are allowed to invest even before ICO offical opens. For testing, for ICO partners, etc. */\n mapping (address => WhiteListData) public earlyParticipantWhitelist;\n /** This is for manul testing for the interaction from owner wallet. You can set it to any value and inspect this in blockchain explorer to see that crowdsale interaction works. */\n uint public ownerTestValue;\n /** State machine\n *\n * - Preparing: All contract initialization calls and variables have not been set yet\n * - Prefunding: We have not passed start time yet\n * - Funding: Active crowdsale\n * - Success: Minimum funding goal reached\n * - Failure: Minimum funding goal not reached before ending time\n * - Finalized: The finalized has been called and succesfully executed\n * - Refunding: Refunds are loaded on the contract for reclaim.\n */\n enum State{Unknown, Preparing, PreFunding, Funding, Success, Failure, Finalized, Refunding}\n // A new investment was made\n event Invested(address investor, uint weiAmount, uint tokenAmount, uint128 customerId);\n // Refund was processed for a contributor\n event Refund(address investor, uint weiAmount);\n // The rules were changed what kind of investments we accept\n event InvestmentPolicyChanged(bool newRequireCustomerId, bool newRequiredSignedAddress, address newSignerAddress);\n // Address early participation whitelist status changed\n event Whitelisted(address addr, bool status);\n // Crowdsale start time has been changed\n event StartsAtChanged(uint newStartsAt);\n // Crowdsale end time has been changed\n event EndsAtChanged(uint newEndsAt);\n function CrowdsaleExt(address _token, PricingStrategy _pricingStrategy, address _multisigWallet, uint _start, uint _end, uint _minimumFundingGoal, bool _isUpdatable, bool _isWhiteListed) {\n owner = msg.sender;\n token = FractionalERC20Ext(_token);\n setPricingStrategy(_pricingStrategy);\n multisigWallet = _multisigWallet;\n if(multisigWallet == 0) {\n throw;\n }\n if(_start == 0) {\n throw;\n }\n startsAt = _start;\n if(_end == 0) {\n throw;\n }\n endsAt = _end;\n // Don't mess the dates\n if(startsAt >= endsAt) {\n throw;\n }\n // Minimum funding goal can be zero\n minimumFundingGoal = _minimumFundingGoal;\n isUpdatable = _isUpdatable;\n isWhiteListed = _isWhiteListed;\n }\n /**\n * Don't expect to just send in money and get tokens.\n */\n function() payable {\n throw;\n }\n /**\n * Make an investment.\n *\n * Crowdsale must be running for one to invest.\n * We must have not pressed the emergency brake.\n *\n * @param receiver The Ethereum address who receives the tokens\n * @param customerId (optional) UUID v4 to track the successful payments on the server side\n *\n */\n function investInternal(address receiver, uint128 customerId) stopInEmergency private {\n // Determine if it's a good time to accept investment from this participant\n if(getState() == State.PreFunding) {\n // Are we whitelisted for early deposit\n throw;\n } else if(getState() == State.Funding) {\n // Retail participants can only come in when the crowdsale is running\n // pass\n if(isWhiteListed) {\n if(!earlyParticipantWhitelist[receiver].status) {\n throw;\n }\n }\n } else {\n // Unwanted state\n throw;\n }\n uint weiAmount = msg.value;\n // Account presale sales separately, so that they do not count against pricing tranches\n uint tokenAmount = pricingStrategy.calculatePrice(weiAmount, weiRaised - presaleWeiRaised, tokensSold, msg.sender, token.decimals());\n if(tokenAmount == 0) {\n // Dust transaction\n throw;\n }\n if(isWhiteListed) {\n if(tokenAmount < earlyParticipantWhitelist[receiver].minCap && tokenAmountOf[receiver] == 0) {\n // tokenAmount < minCap for investor\n throw;\n }\n if(tokenAmount > earlyParticipantWhitelist[receiver].maxCap) {\n // tokenAmount > maxCap for investor\n throw;\n }\n // Check that we did not bust the investor's cap\n if (isBreakingInvestorCap(receiver, tokenAmount)) {\n throw;\n }\n } else {\n if(tokenAmount < token.minCap() && tokenAmountOf[receiver] == 0) {\n throw;\n }\n }\n // Check that we did not bust the cap\n if(isBreakingCap(weiAmount, tokenAmount, weiRaised, tokensSold)) {\n throw;\n }\n // Update investor\n investedAmountOf[receiver] = investedAmountOf[receiver].plus(weiAmount);\n tokenAmountOf[receiver] = tokenAmountOf[receiver].plus(tokenAmount);\n // Update totals\n weiRaised = weiRaised.plus(weiAmount);\n tokensSold = tokensSold.plus(tokenAmount);\n if(pricingStrategy.isPresalePurchase(receiver)) {\n presaleWeiRaised = presaleWeiRaised.plus(weiAmount);\n }\n if(investedAmountOf[receiver] == 0) {\n // A new investor\n investorCount++;\n }\n assignTokens(receiver, tokenAmount);\n // Pocket the money\n if(!multisigWallet.send(weiAmount)) throw;\n if (isWhiteListed) {\n uint num = 0;\n for (var i = 0; i < joinedCrowdsalesLen; i++) {\n if (this == joinedCrowdsales[i])\n num = i;\n }\n if (num + 1 < joinedCrowdsalesLen) {\n for (var j = num + 1; j < joinedCrowdsalesLen; j++) {\n CrowdsaleExt crowdsale = CrowdsaleExt(joinedCrowdsales[j]);\n crowdsale.updateEarlyParicipantWhitelist(msg.sender, this, tokenAmount);\n }\n }\n }\n // Tell us invest was success\n Invested(receiver, weiAmount, tokenAmount, customerId);\n }\n /**\n * Preallocate tokens for the early investors.\n *\n * Preallocated tokens have been sold before the actual crowdsale opens.\n * This function mints the tokens and moves the crowdsale needle.\n *\n * Investor count is not handled; it is assumed this goes for multiple investors\n * and the token distribution happens outside the smart contract flow.\n *\n * No money is exchanged, as the crowdsale team already have received the payment.\n *\n * @param fullTokens tokens as full tokens - decimal places added internally\n * @param weiPrice Price of a single full token in wei\n *\n */\n function preallocate(address receiver, uint fullTokens, uint weiPrice) public onlyOwner {\n uint tokenAmount = fullTokens * 10**token.decimals();\n uint weiAmount = weiPrice * fullTokens; // This can be also 0, we give out tokens for free\n weiRaised = weiRaised.plus(weiAmount);\n tokensSold = tokensSold.plus(tokenAmount);\n investedAmountOf[receiver] = investedAmountOf[receiver].plus(weiAmount);\n tokenAmountOf[receiver] = tokenAmountOf[receiver].plus(tokenAmount);\n assignTokens(receiver, tokenAmount);\n // Tell us invest was success\n Invested(receiver, weiAmount, tokenAmount, 0);\n }\n /**\n * Allow anonymous contributions to this crowdsale.\n */\n function investWithSignedAddress(address addr, uint128 customerId, uint8 v, bytes32 r, bytes32 s) public payable {\n bytes32 hash = sha256(addr);\n if (ecrecover(hash, v, r, s) != signerAddress) throw;\n if(customerId == 0) throw; // UUIDv4 sanity check\n investInternal(addr, customerId);\n }\n /**\n * Track who is the customer making the payment so we can send thank you email.\n */\n function investWithCustomerId(address addr, uint128 customerId) public payable {\n if(requiredSignedAddress) throw; // Crowdsale allows only server-side signed participants\n if(customerId == 0) throw; // UUIDv4 sanity check\n investInternal(addr, customerId);\n }\n /**\n * Allow anonymous contributions to this crowdsale.\n */\n function invest(address addr) public payable {\n if(requireCustomerId) throw; // Crowdsale needs to track participants for thank you email\n if(requiredSignedAddress) throw; // Crowdsale allows only server-side signed participants\n investInternal(addr, 0);\n }\n /**\n * Invest to tokens, recognize the payer and clear his address.\n *\n */\n function buyWithSignedAddress(uint128 customerId, uint8 v, bytes32 r, bytes32 s) public payable {\n investWithSignedAddress(msg.sender, customerId, v, r, s);\n }\n /**\n * Invest to tokens, recognize the payer.\n *\n */\n function buyWithCustomerId(uint128 customerId) public payable {\n investWithCustomerId(msg.sender, customerId);\n }\n /**\n * The basic entry point to participate the crowdsale process.\n *\n * Pay for funding, get invested tokens back in the sender address.\n */\n function buy() public payable {\n invest(msg.sender);\n }\n /**\n * Finalize a succcesful crowdsale.\n *\n * The owner can triggre a call the contract that provides post-crowdsale actions, like releasing the tokens.\n */\n function finalize() public inState(State.Success) onlyOwner stopInEmergency {\n // Already finalized\n if(finalized) {\n throw;\n }\n // Finalizing is optional. We only call it if we are given a finalizing agent.\n if(address(finalizeAgent) != 0) {\n finalizeAgent.finalizeCrowdsale();\n }\n finalized = true;\n }\n /**\n * Allow to (re)set finalize agent.\n *\n * Design choice: no state restrictions on setting this, so that we can fix fat finger mistakes.\n */\n function setFinalizeAgent(FinalizeAgent addr) onlyOwner {\n finalizeAgent = addr;\n // Don't allow setting bad agent\n if(!finalizeAgent.isFinalizeAgent()) {\n throw;\n }\n }\n /**\n * Set policy do we need to have server-side customer ids for the investments.\n *\n */\n function setRequireCustomerId(bool value) onlyOwner {\n requireCustomerId = value;\n InvestmentPolicyChanged(requireCustomerId, requiredSignedAddress, signerAddress);\n }\n /**\n * Set policy if all investors must be cleared on the server side first.\n *\n * This is e.g. for the accredited investor clearing.\n *\n */\n function setRequireSignedAddress(bool value, address _signerAddress) onlyOwner {\n requiredSignedAddress = value;\n signerAddress = _signerAddress;\n InvestmentPolicyChanged(requireCustomerId, requiredSignedAddress, signerAddress);\n }\n /**\n * Allow addresses to do early participation.\n *\n * TODO: Fix spelling error in the name\n */\n function setEarlyParicipantWhitelist(address addr, bool status, uint minCap, uint maxCap) onlyOwner {\n if (!isWhiteListed) throw;\n earlyParticipantWhitelist[addr] = WhiteListData({status:status, minCap:minCap, maxCap:maxCap});\n Whitelisted(addr, status);\n }\n function setEarlyParicipantsWhitelist(address[] addrs, bool[] statuses, uint[] minCaps, uint[] maxCaps) onlyOwner {\n if (!isWhiteListed) throw;\n for (uint iterator = 0; iterator < addrs.length; iterator++) {\n setEarlyParicipantWhitelist(addrs[iterator], statuses[iterator], minCaps[iterator], maxCaps[iterator]);\n }\n }\n function updateEarlyParicipantWhitelist(address addr, address contractAddr, uint tokensBought) {\n if (tokensBought < earlyParticipantWhitelist[addr].minCap) throw;\n if (!isWhiteListed) throw;\n if (addr != msg.sender && contractAddr != msg.sender) throw;\n uint newMaxCap = earlyParticipantWhitelist[addr].maxCap;\n newMaxCap = newMaxCap.minus(tokensBought);\n earlyParticipantWhitelist[addr] = WhiteListData({status:earlyParticipantWhitelist[addr].status, minCap:0, maxCap:newMaxCap});\n }\n function updateJoinedCrowdsales(address addr) onlyOwner {\n joinedCrowdsales[joinedCrowdsalesLen++] = addr;\n }\n function setLastCrowdsale(address addr) onlyOwner {\n lastCrowdsale = addr;\n }\n function clearJoinedCrowdsales() onlyOwner {\n joinedCrowdsalesLen = 0;\n }\n function updateJoinedCrowdsalesMultiple(address[] addrs) onlyOwner {\n clearJoinedCrowdsales();\n for (uint iter = 0; iter < addrs.length; iter++) {\n if(joinedCrowdsalesLen == joinedCrowdsales.length) {\n joinedCrowdsales.length += 1;\n }\n joinedCrowdsales[joinedCrowdsalesLen++] = addrs[iter];\n if (iter == addrs.length - 1)\n setLastCrowdsale(addrs[iter]);\n }\n }\n function setStartsAt(uint time) onlyOwner {\n if (finalized) throw;\n if (!isUpdatable) throw;\n if(now > time) {\n throw; // Don't change past\n }\n if(time > endsAt) {\n throw;\n }\n CrowdsaleExt lastCrowdsaleCntrct = CrowdsaleExt(lastCrowdsale);\n if (lastCrowdsaleCntrct.finalized()) throw;\n startsAt = time;\n StartsAtChanged(startsAt);\n }\n /**\n * Allow crowdsale owner to close early or extend the crowdsale.\n *\n * This is useful e.g. for a manual soft cap implementation:\n * - after X amount is reached determine manual closing\n *\n * This may put the crowdsale to an invalid state,\n * but we trust owners know what they are doing.\n *\n */\n function setEndsAt(uint time) onlyOwner {\n if (finalized) throw;\n if (!isUpdatable) throw;\n if(now > time) {\n throw; // Don't change past\n }\n if(startsAt > time) {\n throw;\n }\n CrowdsaleExt lastCrowdsaleCntrct = CrowdsaleExt(lastCrowdsale);\n if (lastCrowdsaleCntrct.finalized()) throw;\n uint num = 0;\n for (var i = 0; i < joinedCrowdsalesLen; i++) {\n if (this == joinedCrowdsales[i])\n num = i;\n }\n if (num + 1 < joinedCrowdsalesLen) {\n for (var j = num + 1; j < joinedCrowdsalesLen; j++) {\n CrowdsaleExt crowdsale = CrowdsaleExt(joinedCrowdsales[j]);\n if (time > crowdsale.startsAt()) throw;\n }\n }\n endsAt = time;\n EndsAtChanged(endsAt);\n }\n /**\n * Allow to (re)set pricing strategy.\n *\n * Design choice: no state restrictions on the set, so that we can fix fat finger mistakes.\n */\n function setPricingStrategy(PricingStrategy _pricingStrategy) onlyOwner {\n pricingStrategy = _pricingStrategy;\n // Don't allow setting bad agent\n if(!pricingStrategy.isPricingStrategy()) {\n throw;\n }\n }\n /**\n * Allow to change the team multisig address in the case of emergency.\n *\n * This allows to save a deployed crowdsale wallet in the case the crowdsale has not yet begun\n * (we have done only few test transactions). After the crowdsale is going\n * then multisig address stays locked for the safety reasons.\n */\n function setMultisig(address addr) public onlyOwner {\n // Change\n if(investorCount > MAX_INVESTMENTS_BEFORE_MULTISIG_CHANGE) {\n throw;\n }\n multisigWallet = addr;\n }\n /**\n * Allow load refunds back on the contract for the refunding.\n *\n * The team can transfer the funds back on the smart contract in the case the minimum goal was not reached..\n */\n function loadRefund() public payable inState(State.Failure) {\n if(msg.value == 0) throw;\n loadedRefund = loadedRefund.plus(msg.value);\n }\n /**\n * Investors can claim refund.\n *\n * Note that any refunds from proxy buyers should be handled separately,\n * and not through this contract.\n */\n function refund() public inState(State.Refunding) {\n uint256 weiValue = investedAmountOf[msg.sender];\n if (weiValue == 0) throw;\n investedAmountOf[msg.sender] = 0;\n weiRefunded = weiRefunded.plus(weiValue);\n Refund(msg.sender, weiValue);\n if (!msg.sender.send(weiValue)) throw;\n }\n /**\n * @return true if the crowdsale has raised enough money to be a successful.\n */\n function isMinimumGoalReached() public constant returns (bool reached) {\n return weiRaised >= minimumFundingGoal;\n }\n /**\n * Check if the contract relationship looks good.\n */\n function isFinalizerSane() public constant returns (bool sane) {\n return finalizeAgent.isSane();\n }\n /**\n * Check if the contract relationship looks good.\n */\n function isPricingSane() public constant returns (bool sane) {\n return pricingStrategy.isSane(address(this));\n }\n /**\n * Crowdfund state machine management.\n *\n * We make it a function and do not assign the result to a variable, so there is no chance of the variable being stale.\n */\n function getState() public constant returns (State) {\n if(finalized) return State.Finalized;\n else if (address(finalizeAgent) == 0) return State.Preparing;\n else if (!finalizeAgent.isSane()) return State.Preparing;\n else if (!pricingStrategy.isSane(address(this))) return State.Preparing;\n else if (block.timestamp < startsAt) return State.PreFunding;\n else if (block.timestamp <= endsAt && !isCrowdsaleFull()) return State.Funding;\n else if (isMinimumGoalReached()) return State.Success;\n else if (!isMinimumGoalReached() && weiRaised > 0 && loadedRefund >= weiRaised) return State.Refunding;\n else return State.Failure;\n }\n /** This is for manual testing of multisig wallet interaction */\n function setOwnerTestValue(uint val) onlyOwner {\n ownerTestValue = val;\n }\n /** Interface marker. */\n function isCrowdsale() public constant returns (bool) {\n return true;\n }\n //\n // Modifiers\n //\n /** Modified allowing execution only if the crowdsale is currently running. */\n modifier inState(State state) {\n if(getState() != state) throw;\n _;\n }\n //\n // Abstract functions\n //\n /**\n * Check if the current invested breaks our cap rules.\n *\n *\n * The child contract must define their own cap setting rules.\n * We allow a lot of flexibility through different capping strategies (ETH, token count)\n * Called from invest().\n *\n * @param weiAmount The amount of wei the investor tries to invest in the current transaction\n * @param tokenAmount The amount of tokens we try to give to the investor in the current transaction\n * @param weiRaisedTotal What would be our total raised balance after this transaction\n * @param tokensSoldTotal What would be our total sold tokens count after this transaction\n *\n * @return true if taking this investment would break our cap rules\n */\n function isBreakingCap(uint weiAmount, uint tokenAmount, uint weiRaisedTotal, uint tokensSoldTotal) constant returns (bool limitBroken);\n function isBreakingInvestorCap(address receiver, uint tokenAmount) constant returns (bool limitBroken);\n /**\n * Check if the current crowdsale is full and we can no longer sell any tokens.\n */\n function isCrowdsaleFull() public constant returns (bool);\n /**\n * Create new tokens or transfer issued tokens to the investor depending on the cap model.\n */\n function assignTokens(address receiver, uint tokenAmount) private;\n}\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * This smart contract code is Copyright 2017 TokenMarket Ltd. For more information see https://tokenmarket.net\n *\n * Licensed under the Apache License, version 2.0: https://github.com/TokenMarketNet/ico/blob/master/LICENSE.txt\n */\n/**\n * Standard ERC20 token with Short Hand Attack and approve() race condition mitigation.\n *\n * Based on code by FirstBlood:\n * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol\n */\ncontract StandardToken is ERC20, SafeMath {\n /* Token supply got increased and a new owner received these tokens */\n event Minted(address receiver, uint amount);\n /* Actual balances of token holders */\n mapping(address => uint) balances;\n /* approve() allowances */\n mapping (address => mapping (address => uint)) allowed;\n /* Interface declaration */\n function isToken() public constant returns (bool weAre) {\n return true;\n }\n function transfer(address _to, uint _value) returns (bool success) {\n balances[msg.sender] = safeSub(balances[msg.sender], _value);\n balances[_to] = safeAdd(balances[_to], _value);\n Transfer(msg.sender, _to, _value);\n return true;\n }\n function transferFrom(address _from, address _to, uint _value) returns (bool success) {\n uint _allowance = allowed[_from][msg.sender];\n balances[_to] = safeAdd(balances[_to], _value);\n balances[_from] = safeSub(balances[_from], _value);\n allowed[_from][msg.sender] = safeSub(_allowance, _value);\n Transfer(_from, _to, _value);\n return true;\n }\n function balanceOf(address _owner) constant returns (uint balance) {\n return balances[_owner];\n }\n function approve(address _spender, uint _value) returns (bool success) {\n // To change the approve amount you first have to reduce the addresses`\n // allowance to zero by calling `approve(_spender, 0)` if it is not\n // already 0 to mitigate the race condition described here:\n // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n if ((_value != 0) && (allowed[msg.sender][_spender] != 0)) throw;\n allowed[msg.sender][_spender] = _value;\n Approval(msg.sender, _spender, _value);\n return true;\n }\n function allowance(address _owner, address _spender) constant returns (uint remaining) {\n return allowed[_owner][_spender];\n }\n}\n/**\n * A token that can increase its supply by another contract.\n *\n * This allows uncapped crowdsale by dynamically increasing the supply when money pours in.\n * Only mint agents, contracts whitelisted by owner, can mint new tokens.\n *\n */\ncontract MintableTokenExt is StandardToken, Ownable {\n using SafeMathLibExt for uint;\n bool public mintingFinished = false;\n /** List of agents that are allowed to create new tokens */\n mapping (address => bool) public mintAgents;\n event MintingAgentChanged(address addr, bool state );\n struct ReservedTokensData {\n uint inTokens;\n uint inPercentage;\n }\n mapping (address => ReservedTokensData) public reservedTokensList;\n address[] public reservedTokensDestinations;\n uint public reservedTokensDestinationsLen = 0;\n function setReservedTokensList(address addr, uint inTokens, uint inPercentage) onlyOwner {\n reservedTokensDestinations.push(addr);\n reservedTokensDestinationsLen++;\n reservedTokensList[addr] = ReservedTokensData({inTokens:inTokens, inPercentage:inPercentage});\n }\n function getReservedTokensListValInTokens(address addr) constant returns (uint inTokens) {\n return reservedTokensList[addr].inTokens;\n }\n function getReservedTokensListValInPercentage(address addr) constant returns (uint inPercentage) {\n return reservedTokensList[addr].inPercentage;\n }\n function setReservedTokensListMultiple(address[] addrs, uint[] inTokens, uint[] inPercentage) onlyOwner {\n for (uint iterator = 0; iterator < addrs.length; iterator++) {\n setReservedTokensList(addrs[iterator], inTokens[iterator], inPercentage[iterator]);\n }\n }\n /**\n * Create new tokens and allocate them to an address..\n *\n * Only callably by a crowdsale contract (mint agent).\n */\n function mint(address receiver, uint amount) onlyMintAgent canMint public {\n totalSupply = totalSupply.plus(amount);\n balances[receiver] = balances[receiver].plus(amount);\n // This will make the mint transaction apper in EtherScan.io\n // We can remove this after there is a standardized minting event\n Transfer(0, receiver, amount);\n }\n /**\n * Owner can allow a crowdsale contract to mint new tokens.\n */\n function setMintAgent(address addr, bool state) onlyOwner canMint public {\n mintAgents[addr] = state;\n MintingAgentChanged(addr, state);\n }\n modifier onlyMintAgent() {\n // Only crowdsale contracts are allowed to mint new tokens\n if(!mintAgents[msg.sender]) {\n throw;\n }\n _;\n }\n /** Make sure we are not done yet. */\n modifier canMint() {\n if(mintingFinished) throw;\n _;\n }\n}\n/**\n * ICO crowdsale contract that is capped by amout of tokens.\n *\n * - Tokens are dynamically created during the crowdsale\n *\n *\n */\ncontract MintedTokenCappedCrowdsaleExt is CrowdsaleExt {\n /* Maximum amount of tokens this crowdsale can sell. */\n uint public maximumSellableTokens;\n function MintedTokenCappedCrowdsaleExt(address _token, PricingStrategy _pricingStrategy, address _multisigWallet, uint _start, uint _end, uint _minimumFundingGoal, uint _maximumSellableTokens, bool _isUpdatable, bool _isWhiteListed) CrowdsaleExt(_token, _pricingStrategy, _multisigWallet, _start, _end, _minimumFundingGoal, _isUpdatable, _isWhiteListed) {\n maximumSellableTokens = _maximumSellableTokens;\n }\n // Crowdsale maximumSellableTokens has been changed\n event MaximumSellableTokensChanged(uint newMaximumSellableTokens);\n /**\n * Called from invest() to confirm if the curret investment does not break our cap rule.\n */\n function isBreakingCap(uint weiAmount, uint tokenAmount, uint weiRaisedTotal, uint tokensSoldTotal) constant returns (bool limitBroken) {\n return tokensSoldTotal > maximumSellableTokens;\n }\n function isBreakingInvestorCap(address addr, uint tokenAmount) constant returns (bool limitBroken) {\n if (!isWhiteListed) throw;\n uint maxCap = earlyParticipantWhitelist[addr].maxCap;\n return (tokenAmountOf[addr].plus(tokenAmount)) > maxCap;\n }\n function isCrowdsaleFull() public constant returns (bool) {\n return tokensSold >= maximumSellableTokens;\n }\n /**\n * Dynamically create tokens and assign them to the investor.\n */\n function assignTokens(address receiver, uint tokenAmount) private {\n MintableTokenExt mintableToken = MintableTokenExt(token);\n mintableToken.mint(receiver, tokenAmount);\n }\n function setMaximumSellableTokens(uint tokens) onlyOwner {\n if (finalized) throw;\n if (!isUpdatable) throw;\n CrowdsaleExt lastCrowdsaleCntrct = CrowdsaleExt(lastCrowdsale);\n if (lastCrowdsaleCntrct.finalized()) throw;\n maximumSellableTokens = tokens;\n MaximumSellableTokensChanged(maximumSellableTokens);\n }\n}",
"expected_bytecode": "606060405236156102fb5763ffffffff60e060020a6000350416630226401d811461030957806303ca0eed1461032b57806303f9c7931461034f578063045b1a0c1461036557806304fc7c6d14610398578063062b01ce146103ed5780630a09284a146104115780630cc91bb9146104335780630e1d2ec81461045c57806313f4e977146104805780631865c57d146104a257806319b667da146104d65780631a49803b146104f45780631aae34601461052b57806321d5c0f6146105595780632c2de40a1461058557806332013ac31461059a5780633ad075ea146105be5780634042b66f146105e05780634551dd59146106025780634bb278f3146106265780634f97f97f1461063857806350c6773414610664578063518ab2a81461068257806357dc2658146106a4578063590e1ae3146106c25780635b7633d0146106d45780635da89ac0146107005780635ed7ca5b146107225780636203f09f146107345780636e50eb3f1461075657806378b99c241461076b578063797d94371461079757806379e0f59a146107b95780637c2e08a3146108b65780637f7d711e146108da578063831ed348146108f157806387612102146109035780638d51faec1461090d5780638da5cb5b146109225780639075becf1461094e57806397b150ca1461097a57806399e9376c146109a85780639d3c663f146109c7578063a6f2ae3a146109f7578063a7ba44c314610a01578063af46868214610a25578063b3f05b9714610a47578063b9b8af0b14610a6b578063bede2cac14610a8f578063bf5fc2ee14610abe578063cb16e6d014610ad3578063cb3e64fd14610b0f578063d222dc0414610b21578063d245da2814610b45578063d5d0902114610b6c578063d7e64c0014610b90578063dee846c514610bb2578063ebdfa45514610bd0578063ed68ff2c14610bf2578063ef674e6614610c15578063ef86944314610c39578063f2fde38b14610c64578063f3283fba14610c82578063f486972614610ca0578063f7c00e2f14610ccb578063fc0c546a14610ced575b6103075b60006000fd5b565b005b341561031157fe5b610319610d19565b60408051918252519081900360200190f35b341561033357fe5b61033b610d1f565b604080519115158252519081900360200190f35b610307600160a060020a0360043516610d2d565b005b341561036d57fe5b61033b600160a060020a0360043516602435610d6a565b604080519115158252519081900360200190f35b34156103a057fe5b610307600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750949650610e3295505050505050565b005b34156103f557fe5b61033b610f22565b604080519115158252519081900360200190f35b341561041957fe5b610319610fab565b60408051918252519081900360200190f35b341561043b57fe5b610307600160a060020a03600435166024351515604435606435610fb1565b005b341561046457fe5b61033b611075565b604080519115158252519081900360200190f35b341561048857fe5b61031961107e565b60408051918252519081900360200190f35b34156104aa57fe5b6104b2611084565b604051808260078111156104c257fe5b60ff16815260200191505060405180910390f35b34156104de57fe5b610307600160a060020a0360043516611257565b005b610307600160a060020a03600435166fffffffffffffffffffffffffffffffff6024351660ff60443516606435608435611314565b005b341561053357fe5b610319600160a060020a036004351661142a565b60408051918252519081900360200190f35b341561056157fe5b61056961143c565b60408051600160a060020a039092168252519081900360200190f35b341561058d57fe5b61030760043561144b565b005b34156105a257fe5b610307600160a060020a0360043516602435604435611548565b005b34156105c657fe5b610319611882565b60408051918252519081900360200190f35b34156105e857fe5b610319611888565b60408051918252519081900360200190f35b341561060a57fe5b61033b61188e565b604080519115158252519081900360200190f35b341561062e57fe5b610307611894565b005b341561064057fe5b61056961198a565b60408051600160a060020a039092168252519081900360200190f35b341561066c57fe5b610307600160a060020a0360043516611999565b005b341561068a57fe5b610319611a55565b60408051918252519081900360200190f35b34156106ac57fe5b610307600160a060020a0360043516611a5b565b005b34156106ca57fe5b610307611a97565b005b34156106dc57fe5b610569611bf0565b60408051600160a060020a039092168252519081900360200190f35b341561070857fe5b610319611bff565b60408051918252519081900360200190f35b341561072a57fe5b610307611c05565b005b341561073c57fe5b610319611c49565b60408051918252519081900360200190f35b341561075e57fe5b610307600435611c4f565b005b341561077357fe5b610569611eb6565b60408051600160a060020a039092168252519081900360200190f35b341561079f57fe5b610319611ec5565b60408051918252519081900360200190f35b34156107c157fe5b610307600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750949650611ecb95505050505050565b005b34156108be57fe5b61033b611f87565b604080519115158252519081900360200190f35b34156108e257fe5b6103076004351515611f93565b005b34156108f957fe5b610307612030565b005b610307612055565b005b341561091557fe5b610307600435612104565b005b341561092a57fe5b61056961212a565b60408051600160a060020a039092168252519081900360200190f35b341561095657fe5b610569612139565b60408051600160a060020a039092168252519081900360200190f35b341561098257fe5b610319600160a060020a0360043516612148565b60408051918252519081900360200190f35b6103076fffffffffffffffffffffffffffffffff6004351661215a565b005b34156109cf57fe5b61033b600435602435604435606435612168565b604080519115158252519081900360200190f35b610307612176565b005b3415610a0957fe5b61033b612182565b604080519115158252519081900360200190f35b3415610a2d57fe5b6103196121fa565b60408051918252519081900360200190f35b3415610a4f57fe5b61033b612200565b604080519115158252519081900360200190f35b3415610a7357fe5b61033b612209565b604080519115158252519081900360200190f35b3415610a9757fe5b610569600435612219565b60408051600160a060020a039092168252519081900360200190f35b3415610ac657fe5b61030760043561224b565b005b3415610adb57fe5b610aef600160a060020a0360043516612366565b604080519315158452602084019290925282820152519081900360600190f35b3415610b1757fe5b61030761238b565b005b3415610b2957fe5b61033b6123e3565b604080519115158252519081900360200190f35b3415610b4d57fe5b610307600160a060020a03600435811690602435166044356123f3565b005b3415610b7457fe5b61033b61257b565b604080519115158252519081900360200190f35b3415610b9857fe5b610319612587565b60408051918252519081900360200190f35b3415610bba57fe5b610307600160a060020a036004351661258d565b005b3415610bd857fe5b6103196125f8565b60408051918252519081900360200190f35b3415610bfa57fe5b6103076004351515600160a060020a03602435166125fe565b005b3415610c1d57fe5b61033b6126c2565b604080519115158252519081900360200190f35b610307600160a060020a03600435166fffffffffffffffffffffffffffffffff602435166126d1565b005b3415610c6c57fe5b610307600160a060020a0360043516612717565b005b3415610c8a57fe5b610307600160a060020a03600435166127a2565b005b6103076fffffffffffffffffffffffffffffffff6004351660ff602435166044356064356127f0565b005b3415610cd357fe5b610319612804565b60408051918252519081900360200190f35b3415610cf557fe5b61056961280a565b60408051600160a060020a039092168252519081900360200190f35b60185481565b600f54610100900460ff1681565b600f54610100900460ff1615610d435760006000fd5b60125460a060020a900460ff1615610d5b5760006000fd5b610d66816000612819565b5b50565b600f54600090819062010000900460ff161515610d875760006000fd5b50600160a060020a03831660009081526017602090815260408083206002015460158352818420548251840194909452815160e060020a6366098d4f0281526004810194909452602484018690529051909283927354ca5a7c536dbed5897b78d30a93dcd0e46fbdac926366098d4f926044808201939291829003018186803b1515610e0f57fe5b6102c65a03f41515610e1d57fe5b505050604051805190501191505b5092915050565b6000805433600160a060020a03908116911614610e4f5760006000fd5b610e57612030565b5060005b8151811015610f1c576010546011541415610e84576010805460010190610e829082613141565b505b8181815181101515610e9257fe5b602090810290910101516011805460018101909155601080549091908110610eb657fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506001825103811415610f1257610f128282815181101515610f0357fe5b90602001906020020151611a5b565b5b5b600101610e5b565b5b5b5050565b600354604080516000602091820181905282517f8e768288000000000000000000000000000000000000000000000000000000008152600160a060020a033081166004830152935191949390931692638e76828892602480830193919282900301818787803b1515610f9057fe5b6102c65a03f11515610f9e57fe5b5050604051519150505b90565b60085481565b60005433600160a060020a03908116911614610fcd5760006000fd5b600f5462010000900460ff161515610fe55760006000fd5b604080516060810182528415158082526020808301868152838501868152600160a060020a038a166000818152601785528790209551865460ff19169015151786559151600186015551600290940193909355835192835282015281517fa54714518c5d275fdcd3d2a461e4858e4e8cb04fb93cd0bca9d6d34115f26440929181900390910190a15b5b50505050565b60165460ff1681565b60065481565b600f5460009060ff161561109a57506006610fa8565b600454600160a060020a031615156110b457506001610fa8565b600460009054906101000a9004600160a060020a0316600160a060020a03166382771c8e6000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b151561110f57fe5b6102c65a03f1151561111d57fe5b5050604051511515905061113357506001610fa8565b600354604080516000602091820181905282517f8e768288000000000000000000000000000000000000000000000000000000008152600160a060020a03308116600483015293519390941693638e768288936024808301949391928390030190829087803b15156111a157fe5b6102c65a03f115156111af57fe5b505060405151151590506111c557506001610fa8565b6007544210156111d757506002610fa8565b60085442111580156111ee57506111ec61257b565b155b156111fb57506003610fa8565b611203611f87565b1561121057506004610fa8565b611218611f87565b15801561122757506000600a54115b80156112375750600a54600d5410155b1561124457506007610fa8565b506005610fa8565b5b5b5b5b5b5b5b5b90565b60005433600160a060020a039081169116146112735760006000fd5b60048054600160a060020a031916600160a060020a0383811691909117808355604080516000602091820181905282517f614cb9040000000000000000000000000000000000000000000000000000000081529251939094169463614cb9049483820194929383900390910190829087803b15156112ed57fe5b6102c65a03f115156112fb57fe5b50506040515115159050610d665760006000fd5b5b5b50565b60006002866000604051602001526040518082600160a060020a0316600160a060020a03166c0100000000000000000000000002815260140191505060206040518083038160008661646e5a03f1151561136a57fe5b5050604080518051601354600083815260208085018652938501819052845183815260ff8a1681860152808601899052606081018890529451929550600160a060020a03909116936001936080808301949193601f1983019383900390910191908661646e5a03f115156113da57fe5b5050604051601f190151600160a060020a0316146113f85760006000fd5b6fffffffffffffffffffffffffffffffff851615156114175760006000fd5b6114218686612819565b5b505050505050565b60146020526000908152604090205481565b600454600160a060020a031681565b6000805433600160a060020a039081169116146114685760006000fd5b600f5460ff16156114795760006000fd5b60165460ff16151561148b5760006000fd5b601260009054906101000a9004600160a060020a0316905080600160a060020a031663b3f05b976000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b15156114e957fe5b6102c65a03f115156114f757fe5b50506040515115905061150a5760006000fd5b60198290556040805183815290517f7df545c7a1df0d2a1ba979e94124b026facab86a15ed46b6b4a732d995f9e1829181900360200190a15b5b5050565b60008054819033600160a060020a039081169116146115675760006000fd5b600254604080516000602091820181905282517f313ce5670000000000000000000000000000000000000000000000000000000081529251600160a060020a039094169363313ce5679360048082019493918390030190829087803b15156115cb57fe5b6102c65a03f115156115d957fe5b50505060405180519050600a0a840291508383029050600a547354ca5a7c536dbed5897b78d30a93dcd0e46fbdac6366098d4f9091836000604051602001526040518363ffffffff1660e060020a028152600401808381526020018281526020019250505060206040518083038186803b151561165257fe5b6102c65a03f4151561166057fe5b5050604080518051600a556009546000602092830152825160e060020a6366098d4f02815260048101919091526024810186905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f926044808201939291829003018186803b15156116cb57fe5b6102c65a03f415156116d957fe5b5050604080518051600955600160a060020a0388166000908152601460209081528382205492810191909152825160e060020a6366098d4f02815260048101929092526024820185905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b151561175b57fe5b6102c65a03f4151561176957fe5b5050604080518051600160a060020a03891660009081526014602090815284822092909255601582528381205492820152825160e060020a6366098d4f02815260048101929092526024820186905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b15156117f057fe5b6102c65a03f415156117fe57fe5b50506040805151600160a060020a0388166000908152601560205291909120555061182985836130bd565b60408051600160a060020a0387168152602081018390528082018490526000606082015290517f0396f60aaad038749091d273dc13aaabc63db6e2271c7bad442d5cf25cc433509181900360800190a15b5b5050505050565b60195481565b600a5481565b60015b90565b6004805b6118a0611084565b60078111156118ab57fe5b146118b65760006000fd5b60005433600160a060020a039081169116146118d25760006000fd5b60005460a060020a900460ff16156118ea5760006000fd5b600f5460ff16156118fb5760006000fd5b600454600160a060020a0316156119765760048054604080517f0bf318a30000000000000000000000000000000000000000000000000000000081529051600160a060020a0390921692630bf318a392828201926000929082900301818387803b151561196457fe5b6102c65a03f1151561197257fe5b5050505b600f805460ff191660011790555b5b5b5b50565b601254600160a060020a031681565b60005433600160a060020a039081169116146119b55760006000fd5b60038054600160a060020a031916600160a060020a038381169190911791829055604080516000602091820181905282517f04bbc255000000000000000000000000000000000000000000000000000000008152925194909316936304bbc255936004808501948390030190829087803b15156112ed57fe5b6102c65a03f115156112fb57fe5b50506040515115159050610d665760006000fd5b5b5b50565b60095481565b60005433600160a060020a03908116911614611a775760006000fd5b60128054600160a060020a031916600160a060020a0383161790555b5b50565b60006007805b611aa5611084565b6007811115611ab057fe5b14611abb5760006000fd5b600160a060020a0333166000908152601460205260409020549150811515611ae35760006000fd5b600160a060020a0333166000908152601460209081526040808320839055600e548151830193909352805160e060020a6366098d4f028152600481019390935260248301859052517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac926366098d4f926044808301939192829003018186803b1515611b5f57fe5b6102c65a03f41515611b6d57fe5b5050604080518051600e55600160a060020a03331681526020810185905281517fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d93509081900390910190a1604051600160a060020a0333169083156108fc029084906000818181858888f193505050501515610f1c5760006000fd5b5b5b5050565b601354600160a060020a031681565b600e5481565b60005433600160a060020a03908116911614611c215760006000fd5b6000805474ff0000000000000000000000000000000000000000191660a060020a1790555b5b565b60015481565b60008054819081908190819033600160a060020a03908116911614611c745760006000fd5b600f5460ff1615611c855760006000fd5b60165460ff161515611c975760006000fd5b85421115611ca55760006000fd5b856007541115611cb55760006000fd5b601254604080516000602091820181905282517fb3f05b970000000000000000000000000000000000000000000000000000000081529251600160a060020a039094169850889363b3f05b979360048082019493918390030190829087803b1515611d1c57fe5b6102c65a03f11515611d2a57fe5b505060405151159050611d3d5760006000fd5b60009350600092505b6011548360ff161015611db0576010805460ff8516908110611d6457fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a031630600160a060020a03161415611da4578260ff1693505b5b600190920191611d46565b601154846001011015611e73578360010191505b601154821015611e73576010805483908110611ddc57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316905080600160a060020a031663af4686826000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b1515611e4457fe5b6102c65a03f11515611e5257fe5b5050604051518711159050611e675760006000fd5b5b600190910190611dc4565b5b60088690556040805187815290517fd34bb772c4ae9baa99db852f622773b31c7827e8ee818449fef20d30980bd3109181900360200190a15b5b505050505050565b600354600160a060020a031681565b600d5481565b6000805433600160a060020a03908116911614611ee85760006000fd5b600f5462010000900460ff161515611f005760006000fd5b5060005b845181101561187a57611f758582815181101515611f1e57fe5b906020019060200201518583815181101515611f3657fe5b906020019060200201518584815181101515611f4e57fe5b906020019060200201518585815181101515611f6657fe5b90602001906020020151610fb1565b5b600101611f04565b5b5b5050505050565b600654600a5410155b90565b60005433600160a060020a03908116911614611faf5760006000fd5b600f805461ff001916610100831515810291909117918290556012546013546040805160ff9490950484161515855260a060020a90920490921615156020840152600160a060020a0390911682820152517f48d826081348f5f00e8a33c9ae8ce89ed4c6e88400b585a478bc203d9e8177d3916060908290030190a15b5b50565b60005433600160a060020a0390811691161461204c5760006000fd5b60006011555b5b565b6005805b612061611084565b600781111561206c57fe5b146120775760006000fd5b3415156120845760006000fd5b600d547354ca5a7c536dbed5897b78d30a93dcd0e46fbdac6366098d4f9091346000604051602001526040518363ffffffff1660e060020a028152600401808381526020018281526020019250505060206040518083038186803b15156120e757fe5b6102c65a03f415156120f557fe5b505060405151600d55505b5b50565b60005433600160a060020a039081169116146121205760006000fd5b60188190555b5b50565b600054600160a060020a031681565b600554600160a060020a031681565b60156020526000908152604090205481565b610d6633826126d1565b5b50565b60195481115b949350505050565b61030533610d2d565b5b565b6000600460009054906101000a9004600160a060020a0316600160a060020a03166382771c8e6000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b1515610f9057fe5b6102c65a03f11515610f9e57fe5b5050604051519150505b90565b60075481565b600f5460ff1681565b60005460a060020a900460ff1681565b601080548290811061222757fe5b906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805433600160a060020a039081169116146122685760006000fd5b600f5460ff16156122795760006000fd5b60165460ff16151561228b5760006000fd5b814211156122995760006000fd5b6008548211156122a95760006000fd5b601260009054906101000a9004600160a060020a0316905080600160a060020a031663b3f05b976000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b151561230757fe5b6102c65a03f1151561231557fe5b5050604051511590506123285760006000fd5b60078290556040805183815290517fa3f2a813a039e5195c620dabcd490267a9aa5a50e4e1383bc474e9b800f7defe9181900360200190a15b5b5050565b60176020526000908152604090208054600182015460029092015460ff909116919083565b60005433600160a060020a039081169116146123a75760006000fd5b60005460a060020a900460ff1615156123c05760006000fd5b6000805474ff0000000000000000000000000000000000000000191690555b5b5b565b60125460a060020a900460ff1681565b600160a060020a03831660009081526017602052604081206001015482101561241c5760006000fd5b600f5462010000900460ff1615156124345760006000fd5b33600160a060020a031684600160a060020a031614158015612468575033600160a060020a031683600160a060020a031614155b156124735760006000fd5b50600160a060020a038316600090815260176020908152604080832060020154815183019390935280517ff4f3bdc1000000000000000000000000000000000000000000000000000000008152600481018490526024810185905290517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac9263f4f3bdc19260448082019391829003018186803b151561250357fe5b6102c65a03f4151561251157fe5b5050604080518051606082018352600160a060020a038816600081815260176020818152868320805460ff811615158852828801858152988801878152959094529190529351151560ff199091161783559251600183015591516002909101559150505b50505050565b60195460095410155b90565b600c5481565b60005433600160a060020a039081169116146125a95760006000fd5b60118054600181019091556010805483929081106125c357fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055505b5b50565b60115481565b60005433600160a060020a0390811691161461261a5760006000fd5b6012805474ff0000000000000000000000000000000000000000191660a060020a8415158102919091179182905560138054600160a060020a031916600160a060020a038581169190911791829055600f546040805160ff610100909304831615158152949095041615156020840152168183015290517f48d826081348f5f00e8a33c9ae8ce89ed4c6e88400b585a478bc203d9e8177d3916060908290030190a15b5b5050565b600f5462010000900460ff1681565b60125460a060020a900460ff16156126e95760006000fd5b6fffffffffffffffffffffffffffffffff811615156127085760006000fd5b610f1c8282612819565b5b5050565b60005433600160a060020a039081169116146127335760006000fd5b600160a060020a03811615156127495760006000fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a360008054600160a060020a031916600160a060020a0383161790555b5b50565b60005433600160a060020a039081169116146127be5760006000fd5b600154600c5411156127d05760006000fd5b60058054600160a060020a031916600160a060020a0383161790555b5b50565b61106e3385858585611314565b5b50505050565b600b5481565b600254600160a060020a031681565b600060006000600060006000600060149054906101000a900460ff16156128405760006000fd5b60025b61284b611084565b600781111561285657fe5b14156128625760006000fd5b60035b61286d611084565b600781111561287857fe5b14156102ff57600f5462010000900460ff16156128b757600160a060020a03881660009081526017602052604090205460ff1615156128b75760006000fd5b5b6128c3565b60006000fd5b5b349550600360009054906101000a9004600160a060020a0316600160a060020a03166318a4155e87600b54600a540360095433600260009054906101000a9004600160a060020a0316600160a060020a031663313ce5676000604051602001526040518163ffffffff1660e060020a028152600401809050602060405180830381600087803b151561295257fe5b6102c65a03f1151561296057fe5b505050604051805190506000604051602001526040518663ffffffff1660e060020a0281526004018086815260200185815260200184815260200183600160a060020a0316600160a060020a0316815260200182815260200195505050505050602060405180830381600087803b15156129d657fe5b6102c65a03f115156129e457fe5b5050604051519550508415156129fa5760006000fd5b600f5462010000900460ff1615612a9957600160a060020a03881660009081526017602052604090206001015485108015612a4b5750600160a060020a038816600090815260156020526040902054155b15612a565760006000fd5b600160a060020a038816600090815260176020526040902060020154851115612a7f5760006000fd5b612a898886610d6a565b15612a945760006000fd5b612b42565b600254604080516000602091820181905282517f3fa615b00000000000000000000000000000000000000000000000000000000081529251600160a060020a0390941693633fa615b09360048082019493918390030190829087803b1515612afd57fe5b6102c65a03f11515612b0b57fe5b505060405151861090508015612b375750600160a060020a038816600090815260156020526040902054155b15612b425760006000fd5b5b612b538686600a54600954612168565b15612b5e5760006000fd5b600160a060020a0388166000908152601460209081526040808320548151830193909352805160e060020a6366098d4f028152600481019390935260248301899052517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac926366098d4f926044808301939192829003018186803b1515612bd557fe5b6102c65a03f41515612be357fe5b5050604080518051600160a060020a038c1660009081526014602090815284822092909255601582528381205492820152825160e060020a6366098d4f02815260048101929092526024820189905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b1515612c6a57fe5b6102c65a03f41515612c7857fe5b5050604080518051600160a060020a038c1660009081526015602090815284822092909255600a5492820152825160e060020a6366098d4f0281526004810192909252602482018a905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f92604480840193919291829003018186803b1515612cfa57fe5b6102c65a03f41515612d0857fe5b5050604080518051600a556009546000602092830152825160e060020a6366098d4f02815260048101919091526024810189905291517354ca5a7c536dbed5897b78d30a93dcd0e46fbdac93506366098d4f926044808201939291829003018186803b1515612d7357fe5b6102c65a03f41515612d8157fe5b50506040805180516009556003546000602092830181905283517ff14ae17d000000000000000000000000000000000000000000000000000000008152600160a060020a038e81166004830152945194909216945063f14ae17d93602480840194939192918390030190829087803b1515612df857fe5b6102c65a03f11515612e0657fe5b505060405151159050612e8f57600b547354ca5a7c536dbed5897b78d30a93dcd0e46fbdac6366098d4f9091886000604051602001526040518363ffffffff1660e060020a028152600401808381526020018281526020019250505060206040518083038186803b1515612e7657fe5b6102c65a03f41515612e8457fe5b505060405151600b55505b600160a060020a0388166000908152601460205260409020541515612eb857600c805460010190555b612ec288866130bd565b600554604051600160a060020a039091169087156108fc029088906000818181858888f193505050501515612ef75760006000fd5b600f5462010000900460ff161561304e5760009350600092505b6011548360ff161015612f7b576010805460ff8516908110612f2f57fe5b906000526020600020900160005b9054906101000a9004600160a060020a0316600160a060020a031630600160a060020a03161415612f6f578260ff1693505b5b600190920191612f11565b60115484600101101561304e578360010191505b60115482101561304e576010805483908110612fa757fe5b906000526020600020900160005b9054604080517fd245da28000000000000000000000000000000000000000000000000000000008152600160a060020a0333811660048301523081166024830152604482018a905291516101009490940a909204169250829163d245da289160648082019260009290919082900301818387803b151561303157fe5b6102c65a03f1151561303f57fe5b5050505b600190910190612f8f565b5b5b60408051600160a060020a038a168152602081018890528082018790526fffffffffffffffffffffffffffffffff8916606082015290517f0396f60aaad038749091d273dc13aaabc63db6e2271c7bad442d5cf25cc433509181900360800190a15b5b5050505050505050565b600254604080517f40c10f19000000000000000000000000000000000000000000000000000000008152600160a060020a038581166004830152602482018590529151919092169182916340c10f199160448082019260009290919082900301818387803b151561312a57fe5b6102c65a03f1151561142157fe5b5050505b505050565b81548183558181151161313c5760008381526020902061313c91810190830161316b565b5b505050565b610fa891905b808211156131855760008155600101613171565b5090565b905600a165627a7a72305820ed633862024bdaf3d7c3ea3a96bea1c3ba68b7f2eaea220072e1a137aac61e3e0029000000000000000000000000ea097a2b1db00627b2fa17460ad260c016016977000000000000000000000000b4bba71e32c3628f0896639da4c5364519a8ca08000000000000000000000000c7e98536e016bdf82203e8d4df5f31b88d5e3ab70000000000000000000000000000000000000000000000000000000059d3b4000000000000000000000000000000000000000000000000000000000059f89dc40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f04ef12cb04cf15800000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000",
+ "tx_input": "6060604052600560015560006009556000600a556000600b556000600c556000600d556000600e55600060115534156200003557fe5b604051610120806200342483398101604090815281516020830151918301516060840151608085015160a086015160c087015160e0880151610100909801519597949593949293919290915b88888888888887875b5b60008054600160a060020a03191633600160a060020a03161790555b60008054600160a060020a03338116600160a060020a03199283161790925560028054928b1692909116919091179055620000f087640100000000620019996200019c82021704565b60058054600160a060020a031916600160a060020a0388811691909117918290551615156200011f5760006000fd5b8415156200012d5760006000fd5b6007859055831515620001405760006000fd5b6008849055600754849010620001565760006000fd5b60068390556016805460ff1916831515179055600f805462ff0000191662010000831515021790555b505050601988905550505050505b5050505050505050506200025c565b60005433600160a060020a03908116911614620001b95760006000fd5b60038054600160a060020a031916600160a060020a038381169190911791829055604080516000602091820181905282517f04bbc255000000000000000000000000000000000000000000000000000000008152925194909316936304bbc255936004808501948390030190829087803b15156200023357fe5b6102c65a03f115156200024257fe5b50506040515115159050620002575760006000fd5b5b5b50565b6131b8806200026c6000396000f300606060405236156102fb5763ffffffff60e060020a6000350416630226401d811461030957806303ca0eed1461032b57806303f9c7931461034f578063045b1a0c1461036557806304fc7c6d14610398578063062b01ce146103ed5780630a09284a146104115780630cc91bb9146104335780630e1d2ec81461045c57806313f4e977146104805780631865c57d146104a257806319b667da146104d65780631a49803b146104f45780631aae34601461052b57806321d5c0f6146105595780632c2de40a1461058557806332013ac31461059a5780633ad075ea146105be5780634042b66f146105e05780634551dd59146106025780634bb278f3146106265780634f97f97f1461063857806350c6773414610664578063518ab2a81461068257806357dc2658146106a4578063590e1ae3146106c25780635b7633d0146106d45780635da89ac0146107005780635ed7ca5b146107225780636203f09f146107345780636e50eb3f1461075657806378b99c241461076b578063797d94371461079757806379e0f59a146107b95780637c2e08a3146108b65780637f7d711e146108da578063831ed348146108f157806387612102146109035780638d51faec1461090d5780638da5cb5b146109225780639075becf1461094e57806397b150ca1461097a57806399e9376c146109a85780639d3c663f146109c7578063a6f2ae3a146109f7578063a7ba44c314610a01578063af46868214610a25578063b3f05b9714610a47578063b9b8af0b14610a6b578063bede2cac14610a8f578063bf5fc2ee14610abe578063cb16e6d014610ad3578063cb3e64fd14610b0f578063d222dc0414610b21578063d245da2814610b45578063d5d0902114610b6c578063d7e64c0014610b90578063dee846c514610bb2578063ebdfa45514610bd0578063ed68ff2c14610bf2578063ef674e6614610c15578063ef86944314610c39578063f2fde38b14610c64578063f3283fba14610c82578063f486972614610ca0578063f7c00e2f14610ccb578063fc0c546a14610ced575b6103075b60006000fd5b565b005b341561031157fe5b610319610d19565b60408051918252519081900360200190f35b341561033357fe5b61033b610d1f565b604080519115158252519081900360200190f35b610307600160a060020a0360043516610d2d565b005b341561036d57fe5b61033b600160a060020a0360043516602435610d6a565b604080519115158252519081900360200190f35b34156103a057fe5b610307600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750949650610e3295505050505050565b005b34156103f557fe5b61033b610f22565b604080519115158252519081900360200190f35b341561041957fe5b610319610fab565b60408051918252519081900360200190f35b341561043b57fe5b610307600160a060020a03600435166024351515604435606435610fb1565b005b341561046457fe5b61033b611075565b604080519115158252519081900360200190f35b341561048857fe5b61031961107e565b60408051918252519081900360200190f35b34156104aa57fe5b6104b2611084565b604051808260078111156104c257fe5b60ff16815260200191505060405180910390f35b34156104de57fe5b610307600160a060020a0360043516611257565b005b610307600160a060020a03600435166fffffffffffffffffffffffffffffffff6024351660ff60443516606435608435611314565b005b341561053357fe5b610319600160a060020a036004351661142a565b60408051918252519081900360200190f35b341561056157fe5b61056961143c565b60408051600160a060020a039092168252519081900360200190f35b341561058d57fe5b61030760043561144b565b005b34156105a257fe5b610307600160a060020a0360043516602435604435611548565b005b34156105c657fe5b610319611882565b60408051918252519081900360200190f35b34156105e857fe5b610319611888565b60408051918252519081900360200190f35b341561060a57fe5b61033b61188e565b604080519115158252519081900360200190f35b341561062e57fe5b610307611894565b005b341561064057fe5b61056961198a565b60408051600160a060020a039092168252519081900360200190f35b341561066c57fe5b610307600160a060020a0360043516611999565b005b341561068a57fe5b610319611a55565b60408051918252519081900360200190f35b34156106ac57fe5b610307600160a060020a0360043516611a5b565b005b34156106ca57fe5b610307611a97565b005b34156106dc57fe5b610569611bf0565b60408051600160a060020a039092168252519081900360200190f35b341561070857fe5b610319611bff565b60408051918252519081900360200190f35b341561072a57fe5b610307611c05565b005b341561073c57fe5b610319611c49565b60408051918252519081900360200190f35b341561075e57fe5b610307600435611c4f565b005b341561077357fe5b610569611eb6565b60408051600160a060020a039092168252519081900360200190f35b341561079f57fe5b610319611ec5565b60408051918252519081900360200190f35b34156107c157fe5b610307600480803590602001908201803590602001908080602002602001604051908101604052809392919081815260200183836020028082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750506040805187358901803560208181028481018201909552818452989a998901989297509082019550935083925085019084908082843750949650611ecb95505050505050565b005b34156108be57fe5b61033b611f87565b604080519115158252519081900360200190f35b34156108e257fe5b6103076004351515611f93565b005b34156108f957fe5b610307612030565b005b610307612055565b005b341561091557fe5b610307600435612104565b005b341561092a57fe5b61056961212a565b60408051600160a060020a039092168252519081900360200190f35b341561095657fe5b610569612139565b60408051600160a060020a039092168252519081900360200190f35b341561098257fe5b610319600160a060020a0360043516612148565b60408051918252519081900360200190f35b6103076fffffffffffffffffffffffffffffffff6004351661215a565b005b34156109cf57fe5b61033b600435602435604435606435612168565b604080519115158252519081900360200190f35b610307612176565b005b3415610a0957fe5b61033b612182565b604080519115158252519081900360200190f35b3415610a2d57fe5b6103196121fa565b60408051918252519081900360200190f35b3415610a4f57fe5b61033b612200565b604080519115158252519081900360200190f35b3415610a7357fe5b61033b612209565b604080519115158252519081900360200190f35b3415610a9757fe5b610569600435612219565b60408051600160a060020a039092168252519081900360200190f35b3415610ac657fe5b61030760043561224b565b005b3415610adb57fe5b610aef600160a060020a0360043516612366565b604080519315158452602084019290925282820152519081900360600190f35b3415610b1757fe5b61030761238b565b005b3415610b2957fe5b61033b6123e3565b604080519115158252519081900360200190f35b3415610b4d57fe5b610307600160a060020a03600435811690602435166044356123f3565b005b3415610b7457fe5b61033b61257b565b604080519115158252519081900360200190f35b3415610b9857fe5b610319612587565b60408051918252519081900360200190f35b3415610bba57fe5b610307600160a060020a036004351661258d565b005b3415610bd857fe5b6103196125f8565b60408051918252519081900360200190f35b3415610bfa57fe5b6103076004351515600160a060020a03602435166125fe565b005b3415610c1d57fe5b61033b6126c2565b604080519115158252519081900360200190f35b610307600160a060020a03600435166fffffffffffffffffffffffffffffffff602435166126d1565b005b3415610c6c57fe5b610307600160a060020a0360043516612717565b005b3415610c8a57fe5b610307600160a060020a03600435166127a2565b005b6103076fffffffffffffffffffffffffffffffff6004351660ff602435166044356064356127f0565b005b3415610cd357fe5b610319612804565b60408051918252519081900360200190f35b3415610cf557fe5b61056961280a565b60408051600160a060020a039092168252519081900360200190f35b60185481565b600f54610100900460ff1681565b600f54610100900460ff1615610d435760006000fd5b60125460a060020a900460ff1615610d5b5760006000fd5b610d66816000612819565b5b50565b600f54600090819062010000900460ff161515610d875760006000fd5b50600160a060020a03831660009081526017602090815260408083206002015460158352818420548251840194909452815160e060020a6366098d4f0281526004810194909452602484018690529051909283927354ca5a7c536dbed5897b78d30a93dcd0e46fbdac926366098d4f926044808201939291829003018186803b1515610e0f57fe5b6102c65a03f41515610e1d57fe5b505050604051805190501191505b5092915050565b6000805433600160a060020a03908116911614610e4f5760006000fd5b610e57612030565b5060005b8151811015610f1c576010546011541415610e84576010805460010190610e829082613141565b505b8181815181101515610e9257fe5b602090810290910101516011805460018101909155601080549091908110610eb657fe5b906000526020600020900160005b6101000a815481600160a060020a030219169083600160a060020a031602179055506001825103811415610f1257610f128282815181101515610f0357fe5b90602001906020020151611a5b565b5b5b600101610e5b565b5b5b5050565b600354604080516000602091820181905282517f8e768288000000000000000000000000000000000000000000000000000000008152600160a060020a033081166004830152935191949390931692638e76828892602480830193919282900301818787803b1515610f9057fe5b6102c65a03f11515610f9e57fe5b5050604051519150505b90565b60085481565b60005433600160a060020a03908116911614610fcd5760006000fd5b600f5462010000900460ff161515610fe55760006000fd5b604080516060810182528415158082526020808301868152838501868152600160a060020a038a1660008415158082526020808301868152838501868152600160a060020a038a1660008",
"external_libraries": {
"SafeMathLibExt": "0x54ca5a7c536dbed5897b78d30a93dcd0e46fbdac"
},
diff --git a/apps/explorer/test/support/fixture/smart_contract/contract_from_factory.sol b/apps/explorer/test/support/fixture/smart_contract/contract_from_factory.sol
new file mode 100644
index 0000000000..bf85d70c51
--- /dev/null
+++ b/apps/explorer/test/support/fixture/smart_contract/contract_from_factory.sol
@@ -0,0 +1,18 @@
+pragma solidity 0.4.26;
+
+contract Factory {
+ address[] newContracts;
+
+ function createContract (bytes32 name) public {
+ address newContract = new ContractFromFactory(name);
+ newContracts.push(newContract);
+ }
+}
+
+contract ContractFromFactory {
+ bytes32 public Name;
+
+ constructor(bytes32 name) public {
+ Name = name;
+ }
+}
\ No newline at end of file
diff --git a/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.json b/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.json
index aba02b0ec4..cd625952b0 100644
--- a/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.json
+++ b/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.json
@@ -3,11 +3,11 @@
"compiler_version": "v0.5.11+commit.c082d0b4",
"contract": "pragma solidity 0.5.11;library BadSafeMath { function add(uint256 a, uint256 b) public pure returns (uint256) { uint256 c = a + 2 * b; require(c >= a, \"SafeMath: addition overflow\"); return c; }}contract SimpleStorage { uint256 storedData = 10; using BadSafeMath for uint256; function increment(uint256 x) public { storedData = storedData.add(x); } function set(uint256 x) public { storedData = x; } function get() public view returns (uint256) { return storedData; }}",
"expected_bytecode": "608060405234801561001057600080fd5b50600436106100415760003560e01c806360fe47b1146100465780636d4ce63c146100655780637cf5dab01461007f575b600080fd5b6100636004803603602081101561005c57600080fd5b503561009c565b005b61006d6100a1565b60408051918252519081900360200190f35b6100636004803603602081101561009557600080fd5b50356100a7565b600055565b60005490565b600054733662e222908fa35f013bee37695d0510098b6d7363771602f79091836040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561010257600080fd5b505af4158015610116573d6000803e3d6000fd5b505050506040513d602081101561012c57600080fd5b50516000555056fea265627a7a723158203e59bfb9a5a2e55d38231922c86d8b2ec9b66cb2f6595613674bc4e15290b60764736f6c634300050b0032",
+ "tx_input": "6080604052600a60005534801561001557600080fd5b50610169806100256000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806360fe47b1146100465780636d4ce63c146100655780637cf5dab01461007f575b600080fd5b6100636004803603602081101561005c57600080fd5b503561009c565b005b61006d6100a1565b60408051918252519081900360200190f35b6100636004803603602081101561009557600080fd5b50356100a7565b600055565b60005490565b600054733662e222908fa35f013bee37695d0510098b6d7363771602f79091836040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561010257600080fd5b505af4158015610116573d6000803e3d6000fd5b505050506040513d602081101561012c57600080fd5b50516000555056fea265627a7a723158207809bc828bbcd3de3e6b6483facb0c5902901fc8827283c749c8ea0702eb871f64736f6c634300050b0032",
"external_libraries": {
"BadSafeMath": "0x3662e222908fa35f013bee37695d0510098b6d73"
},
"name": "SimpleStorage",
"optimize": true
}
- ]
-
\ No newline at end of file
+ ]
\ No newline at end of file
diff --git a/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.sol b/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.sol
new file mode 100644
index 0000000000..7b80cef397
--- /dev/null
+++ b/apps/explorer/test/support/fixture/smart_contract/contract_with_lib.sol
@@ -0,0 +1,25 @@
+pragma solidity 0.5.11;
+
+library BadSafeMath {
+ function add(uint256 a, uint256 b) public pure returns (uint256) {
+ uint256 c = a + 2 * b;
+ require(c >= a, "SafeMath: addition overflow");
+ return c;
+ }
+}
+
+contract SimpleStorage {
+ uint256 storedData = 10;
+ using BadSafeMath for uint256;
+ function increment(uint256 x) public {
+ storedData = storedData.add(x);
+ }
+
+ function set(uint256 x) public {
+ storedData = x;
+ }
+
+ function get() public view returns (uint256) {
+ return storedData;
+ }
+}
\ No newline at end of file
diff --git a/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.json b/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.json
index bd0301ef78..04985d44a4 100644
--- a/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.json
+++ b/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.json
@@ -1,5 +1,6 @@
{
"bytecode": "608060405260043610610105576000357c0100000000000000000000000000000000000000000000000000000000900480638da5cb5b116100a7578063d4ee1d9011610076578063d4ee1d90146105dc578063dc39d06d14610633578063dd62ed3e146106a6578063f2fde38b1461072b57610105565b80638da5cb5b1461037857806395d89b41146103cf578063a9059cbb1461045f578063cae9ca51146104d257610105565b806323b872dd116100e357806323b872dd14610238578063313ce567146102cb57806370a08231146102fc57806379ba50971461036157610105565b806306fdde031461010a578063095ea7b31461019a57806318160ddd1461020d575b600080fd5b34801561011657600080fd5b5061011f61077c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015f578082015181840152602081019050610144565b50505050905090810190601f16801561018c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156101a657600080fd5b506101f3600480360360408110156101bd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061081a565b604051808215151515815260200191505060405180910390f35b34801561021957600080fd5b5061022261090c565b6040518082815260200191505060405180910390f35b34801561024457600080fd5b506102b16004803603606081101561025b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610967565b604051808215151515815260200191505060405180910390f35b3480156102d757600080fd5b506102e0610c12565b604051808260ff1660ff16815260200191505060405180910390f35b34801561030857600080fd5b5061034b6004803603602081101561031f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c25565b6040518082815260200191505060405180910390f35b34801561036d57600080fd5b50610376610c6e565b005b34801561038457600080fd5b5061038d610e0b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156103db57600080fd5b506103e4610e30565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610424578082015181840152602081019050610409565b50505050905090810190601f1680156104515780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561046b57600080fd5b506104b86004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610ece565b604051808215151515815260200191505060405180910390f35b3480156104de57600080fd5b506105c2600480360360608110156104f557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561053c57600080fd5b82018360208201111561054e57600080fd5b8035906020019184600183028401116401000000008311171561057057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611069565b604051808215151515815260200191505060405180910390f35b3480156105e857600080fd5b506105f16112b8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561063f57600080fd5b5061068c6004803603604081101561065657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506112de565b604051808215151515815260200191505060405180910390f35b3480156106b257600080fd5b50610715600480360360408110156106c957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611440565b6040518082815260200191505060405180910390f35b34801561073757600080fd5b5061077a6004803603602081101561074e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114c7565b005b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108125780601f106107e757610100808354040283529160200191610812565b820191906000526020600020905b8154815290600101906020018083116107f557829003601f168201915b505050505081565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000610962600660008073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460055461156490919063ffffffff16565b905090565b60006109bb82600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461156490919063ffffffff16565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610a8d82600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461156490919063ffffffff16565b600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b5f82600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461157e90919063ffffffff16565b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b600460009054906101000a900460ff1681565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610cc857600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60028054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ec65780601f10610e9b57610100808354040283529160200191610ec6565b820191906000526020600020905b815481529060010190602001808311610ea957829003601f168201915b505050505081565b6000610f2282600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461156490919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610fb782600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461157e90919063ffffffff16565b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b600082600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561124657808201518184015260208101905061122b565b50505050905090810190601f1680156112735780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561129557600080fd5b505af11580156112a9573d6000803e3d6000fd5b50505050600190509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461133957600080fd5b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156113fd57600080fd5b505af1158015611411573d6000803e3d6000fd5b505050506040513d602081101561142757600080fd5b8101908080519060200190929190505050905092915050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461152057600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008282111561157357600080fd5b818303905092915050565b600081830190508281101561159257600080fd5b9291505056fea265627a7a7231582073fbadbc806cc1f3349b3f98d58b62f7fa417e82d98f41bafd3dd9f9be4e4fa764736f6c634300050b0032",
+ "input": "60806040523480156200001157600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506040518060400160405280600481526020017f5445535400000000000000000000000000000000000000000000000000000000815250600290805190602001906200009f92919062000221565b506040518060400160405280600a81526020017f5465737420546f6b656e0000000000000000000000000000000000000000000081525060039080519060200190620000ed92919062000221565b506012600460006101000a81548160ff021916908360ff160217905550600460009054906101000a900460ff1660ff16600a0a620f424002600581905550600554600660008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6005546040518082815260200191505060405180910390a3620002d0565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200026457805160ff191683800117855562000295565b8280016001018555821562000295579182015b828111156200029457825182559160200191906001019062000277565b5b509050620002a49190620002a8565b5090565b620002cd91905b80821115620002c9576000816000905550600101620002af565b5090565b90565b6115cd80620002e06000396000f3fe608060405260043610610105576000357c0100000000000000000000000000000000000000000000000000000000900480638da5cb5b116100a7578063d4ee1d9011610076578063d4ee1d90146105dc578063dc39d06d14610633578063dd62ed3e146106a6578063f2fde38b1461072b57610105565b80638da5cb5b1461037857806395d89b41146103cf578063a9059cbb1461045f578063cae9ca51146104d257610105565b806323b872dd116100e357806323b872dd14610238578063313ce567146102cb57806370a08231146102fc57806379ba50971461036157610105565b806306fdde031461010a578063095ea7b31461019a57806318160ddd1461020d575b600080fd5b34801561011657600080fd5b5061011f61077c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015f578082015181840152602081019050610144565b50505050905090810190601f16801561018c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156101a657600080fd5b506101f3600480360360408110156101bd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061081a565b604051808215151515815260200191505060405180910390f35b34801561021957600080fd5b5061022261090c565b6040518082815260200191505060405180910390f35b34801561024457600080fd5b506102b16004803603606081101561025b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610967565b604051808215151515815260200191505060405180910390f35b3480156102d757600080fd5b506102e0610c12565b604051808260ff1660ff16815260200191505060405180910390f35b34801561030857600080fd5b5061034b6004803603602081101561031f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c25565b6040518082815260200191505060405180910390f35b34801561036d57600080fd5b50610376610c6e565b005b34801561038457600080fd5b5061038d610e0b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156103db57600080fd5b506103e4610e30565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610424578082015181840152602081019050610409565b50505050905090810190601f1680156104515780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561046b57600080fd5b506104b86004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610ece565b604051808215151515815260200191505060405180910390f35b3480156104de57600080fd5b506105c2600480360360608110156104f557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019064010000000081111561053c57600080fd5b82018360208201111561054e57600080fd5b8035906020019184600183028401116401000000008311171561057057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611069565b604051808215151515815260200191505060405180910390f35b3480156105e857600080fd5b506105f16112b8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561063f57600080fd5b5061068c6004803603604081101561065657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506112de565b604051808215151515815260200191505060405180910390f35b3480156106b257600080fd5b50610715600480360360408110156106c957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611440565b6040518082815260200191505060405180910390f35b34801561073757600080fd5b5061077a6004803603602081101561074e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114c7565b005b60038054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108125780601f106107e757610100808354040283529160200191610812565b820191906000526020600020905b8154815290600101906020018083116107f557829003601f168201915b505050505081565b600081600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000610962600660008073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205460055461156490919063ffffffff16565b905090565b60006109bb82600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461156490919063ffffffff16565b600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610a8d82600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461156490919063ffffffff16565b600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b5f82600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461157e90919063ffffffff16565b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b600460009054906101000a900460ff1681565b6000600660008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610cc857600080fd5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60028054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ec65780601f10610e9b57610100808354040283529160200191610ec6565b820191906000526020600020905b815481529060010190602001808311610ea957829003601f168201915b505050505081565b6000610f2282600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461156490919063ffffffff16565b600660003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610fb782600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461157e90919063ffffffff16565b600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b600082600760003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561124657808201518184015260208101905061122b565b50505050905090810190601f1680156112735780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b15801561129557600080fd5b505af11580156112a9573d6000803e3d6000fd5b50505050600190509392505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461133957600080fd5b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156113fd57600080fd5b505af1158015611411573d6000803e3d6000fd5b505050506040513d602081101561142757600080fd5b8101908080519060200190929190505050905092915050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461152057600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008282111561157357600080fd5b818303905092915050565b600081830190508281101561159257600080fd5b9291505056fea265627a7a7231582017ad0fd486aac012abf90ff8ce3c9d571dcbf654bf184da3a8e67daea3e43fbd64736f6c634300050b0032",
"compiler_version": "v0.5.11+commit.c082d0b4",
"contract": "/**\r\n *Submitted for verification at Etherscan.io on 2019-08-16\r\n*/\r\n\r\npragma solidity ^0.5.0;\r\n\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n// 'FIXED' 'Example Fixed Supply Token' token contract\r\n\r\n//\r\n\r\n// Symbol : FIXED\r\n\r\n// Name : Example Fixed Supply Token\r\n\r\n// Total supply: 1,000,000.000000000000000000\r\n\r\n// Decimals : 18\r\n\r\n//\r\n\r\n// Enjoy.\r\n\r\n//\r\n\r\n// (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. The MIT Licence.\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n// Safe maths\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\nlibrary SafeMath {\r\n\r\n function add(uint a, uint b) internal pure returns (uint c) {\r\n\r\n c = a + b;\r\n\r\n require(c >= a);\r\n\r\n }\r\n\r\n function sub(uint a, uint b) internal pure returns (uint c) {\r\n\r\n require(b <= a);\r\n\r\n c = a - b;\r\n\r\n }\r\n\r\n function mul(uint a, uint b) internal pure returns (uint c) {\r\n\r\n c = a * b;\r\n\r\n require(a == 0 || c / a == b);\r\n\r\n }\r\n\r\n function div(uint a, uint b) internal pure returns (uint c) {\r\n\r\n require(b > 0);\r\n\r\n c = a / b;\r\n\r\n }\r\n\r\n}\r\n\r\n\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n// ERC Token Standard #20 Interface\r\n\r\n// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\ncontract ERC20Interface {\r\n\r\n function totalSupply() public view returns (uint);\r\n\r\n function balanceOf(address tokenOwner) public view returns (uint balance);\r\n\r\n function allowance(address tokenOwner, address spender) public view returns (uint remaining);\r\n\r\n function transfer(address to, uint tokens) public returns (bool success);\r\n\r\n function approve(address spender, uint tokens) public returns (bool success);\r\n\r\n function transferFrom(address from, address to, uint tokens) public returns (bool success);\r\n\r\n\r\n event Transfer(address indexed from, address indexed to, uint tokens);\r\n\r\n event Approval(address indexed tokenOwner, address indexed spender, uint tokens);\r\n\r\n}\r\n\r\n\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n// Contract function to receive approval and execute function in one call\r\n\r\n//\r\n\r\n// Borrowed from MiniMeToken\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\ncontract ApproveAndCallFallBack {\r\n\r\n function receiveApproval(address from, uint256 tokens, address token, bytes memory data) public;\r\n\r\n}\r\n\r\n\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n// Owned contract\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\ncontract Owned {\r\n\r\n address public owner;\r\n\r\n address public newOwner;\r\n\r\n\r\n event OwnershipTransferred(address indexed _from, address indexed _to);\r\n\r\n\r\n constructor() public {\r\n\r\n owner = msg.sender;\r\n\r\n }\r\n\r\n\r\n modifier onlyOwner {\r\n\r\n require(msg.sender == owner);\r\n\r\n _;\r\n\r\n }\r\n\r\n\r\n function transferOwnership(address _newOwner) public onlyOwner {\r\n\r\n newOwner = _newOwner;\r\n\r\n }\r\n\r\n function acceptOwnership() public {\r\n\r\n require(msg.sender == newOwner);\r\n\r\n emit OwnershipTransferred(owner, newOwner);\r\n\r\n owner = newOwner;\r\n\r\n newOwner = address(0);\r\n\r\n }\r\n\r\n}\r\n\r\n\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\n// ERC20 Token, with the addition of symbol, name and decimals and a\r\n\r\n// fixed supply\r\n\r\n// ----------------------------------------------------------------------------\r\n\r\ncontract FixedSupplyToken is ERC20Interface, Owned {\r\n\r\n using SafeMath for uint;\r\n\r\n\r\n string public symbol;\r\n\r\n string public name;\r\n\r\n uint8 public decimals;\r\n\r\n uint _totalSupply;\r\n\r\n\r\n mapping(address => uint) balances;\r\n\r\n mapping(address => mapping(address => uint)) allowed;\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Constructor\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n constructor() public {\r\n\r\n symbol = \"TEST\";\r\n\r\n name = \"Test Token\";\r\n\r\n decimals = 18;\r\n\r\n _totalSupply = 1000000 * 10**uint(decimals);\r\n\r\n balances[owner] = _totalSupply;\r\n\r\n emit Transfer(address(0), owner, _totalSupply);\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Total supply\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function totalSupply() public view returns (uint) {\r\n\r\n return _totalSupply.sub(balances[address(0)]);\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Get the token balance for account `tokenOwner`\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function balanceOf(address tokenOwner) public view returns (uint balance) {\r\n\r\n return balances[tokenOwner];\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Transfer the balance from token owner's account to `to` account\r\n\r\n // - Owner's account must have sufficient balance to transfer\r\n\r\n // - 0 value transfers are allowed\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function transfer(address to, uint tokens) public returns (bool success) {\r\n\r\n balances[msg.sender] = balances[msg.sender].sub(tokens);\r\n\r\n balances[to] = balances[to].add(tokens);\r\n\r\n emit Transfer(msg.sender, to, tokens);\r\n\r\n return true;\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Token owner can approve for `spender` to transferFrom(...) `tokens`\r\n\r\n // from the token owner's account\r\n\r\n //\r\n\r\n // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md\r\n\r\n // recommends that there are no checks for the approval double-spend attack\r\n\r\n // as this should be implemented in user interfaces\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function approve(address spender, uint tokens) public returns (bool success) {\r\n\r\n allowed[msg.sender][spender] = tokens;\r\n\r\n emit Approval(msg.sender, spender, tokens);\r\n\r\n return true;\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Transfer `tokens` from the `from` account to the `to` account\r\n\r\n //\r\n\r\n // The calling account must already have sufficient tokens approve(...)-d\r\n\r\n // for spending from the `from` account and\r\n\r\n // - From account must have sufficient balance to transfer\r\n\r\n // - Spender must have sufficient allowance to transfer\r\n\r\n // - 0 value transfers are allowed\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function transferFrom(address from, address to, uint tokens) public returns (bool success) {\r\n\r\n balances[from] = balances[from].sub(tokens);\r\n\r\n allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);\r\n\r\n balances[to] = balances[to].add(tokens);\r\n\r\n emit Transfer(from, to, tokens);\r\n\r\n return true;\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Returns the amount of tokens approved by the owner that can be\r\n\r\n // transferred to the spender's account\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function allowance(address tokenOwner, address spender) public view returns (uint remaining) {\r\n\r\n return allowed[tokenOwner][spender];\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Token owner can approve for `spender` to transferFrom(...) `tokens`\r\n\r\n // from the token owner's account. The `spender` contract function\r\n\r\n // `receiveApproval(...)` is then executed\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function approveAndCall(address spender, uint tokens, bytes memory data) public returns (bool success) {\r\n\r\n allowed[msg.sender][spender] = tokens;\r\n\r\n emit Approval(msg.sender, spender, tokens);\r\n\r\n ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, address(this), data);\r\n\r\n return true;\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Don't accept ETH\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function () external payable {\r\n\r\n revert();\r\n\r\n }\r\n\r\n\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n // Owner can transfer out any accidentally sent ERC20 tokens\r\n\r\n // ------------------------------------------------------------------------\r\n\r\n function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {\r\n\r\n return ERC20Interface(tokenAddress).transfer(owner, tokens);\r\n\r\n }\r\n\r\n}",
"name": "FixedSupplyToken",
diff --git a/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.sol b/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.sol
new file mode 100644
index 0000000000..c72c22650c
--- /dev/null
+++ b/apps/explorer/test/support/fixture/smart_contract/solidity_5.11_new_whisper_metadata.sol
@@ -0,0 +1,412 @@
+/** *Submitted for verification at Etherscan.io on 2019-08-16
+*/
+
+pragma solidity ^0.5.0;
+
+
+// ----------------------------------------------------------------------------
+
+// 'FIXED' 'Example Fixed Supply Token' token contract
+
+//
+
+// Symbol : FIXED
+
+// Name : Example Fixed Supply Token
+
+// Total supply: 1,000,000.000000000000000000
+
+// Decimals : 18
+
+//
+
+// Enjoy.
+
+//
+
+// (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. The MIT Licence.
+
+// ----------------------------------------------------------------------------
+
+
+
+// ----------------------------------------------------------------------------
+
+// Safe maths
+
+// ----------------------------------------------------------------------------
+
+library SafeMath {
+
+ function add(uint a, uint b) internal pure returns (uint c) {
+
+ c = a + b;
+
+ require(c >= a);
+
+ }
+
+ function sub(uint a, uint b) internal pure returns (uint c) {
+
+ require(b <= a);
+
+ c = a - b;
+
+ }
+
+ function mul(uint a, uint b) internal pure returns (uint c) {
+
+ c = a * b;
+
+ require(a == 0 || c / a == b);
+
+ }
+
+ function div(uint a, uint b) internal pure returns (uint c) {
+
+ require(b > 0);
+
+ c = a / b;
+
+ }
+
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+// ERC Token Standard #20 Interface
+
+// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
+
+// ----------------------------------------------------------------------------
+
+contract ERC20Interface {
+
+ function totalSupply() public view returns (uint);
+
+ function balanceOf(address tokenOwner) public view returns (uint balance);
+
+ function allowance(address tokenOwner, address spender) public view returns (uint remaining);
+
+ function transfer(address to, uint tokens) public returns (bool success);
+
+ function approve(address spender, uint tokens) public returns (bool success);
+
+ function transferFrom(address from, address to, uint tokens) public returns (bool success);
+
+
+ event Transfer(address indexed from, address indexed to, uint tokens);
+
+ event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
+
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+// Contract function to receive approval and execute function in one call
+
+//
+
+// Borrowed from MiniMeToken
+
+// ----------------------------------------------------------------------------
+
+contract ApproveAndCallFallBack {
+
+ function receiveApproval(address from, uint256 tokens, address token, bytes memory data) public;
+
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+// Owned contract
+
+// ----------------------------------------------------------------------------
+
+contract Owned {
+
+ address public owner;
+
+ address public newOwner;
+
+
+ event OwnershipTransferred(address indexed _from, address indexed _to);
+
+
+ constructor() public {
+
+ owner = msg.sender;
+
+ }
+
+
+ modifier onlyOwner {
+
+ require(msg.sender == owner);
+
+ _;
+
+ }
+
+
+ function transferOwnership(address _newOwner) public onlyOwner {
+
+ newOwner = _newOwner;
+
+ }
+
+ function acceptOwnership() public {
+
+ require(msg.sender == newOwner);
+
+ emit OwnershipTransferred(owner, newOwner);
+
+ owner = newOwner;
+
+ newOwner = address(0);
+
+ }
+
+}
+
+
+
+// ----------------------------------------------------------------------------
+
+// ERC20 Token, with the addition of symbol, name and decimals and a
+
+// fixed supply
+
+// ----------------------------------------------------------------------------
+
+contract FixedSupplyToken is ERC20Interface, Owned {
+
+ using SafeMath for uint;
+
+
+ string public symbol;
+
+ string public name;
+
+ uint8 public decimals;
+
+ uint _totalSupply;
+
+
+ mapping(address => uint) balances;
+
+ mapping(address => mapping(address => uint)) allowed;
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Constructor
+
+ // ------------------------------------------------------------------------
+
+ constructor() public {
+
+ symbol = "TEST";
+
+ name = "Test Token";
+
+ decimals = 18;
+
+ _totalSupply = 1000000 * 10**uint(decimals);
+
+ balances[owner] = _totalSupply;
+
+ emit Transfer(address(0), owner, _totalSupply);
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Total supply
+
+ // ------------------------------------------------------------------------
+
+ function totalSupply() public view returns (uint) {
+
+ return _totalSupply.sub(balances[address(0)]);
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Get the token balance for account `tokenOwner`
+
+ // ------------------------------------------------------------------------
+
+ function balanceOf(address tokenOwner) public view returns (uint balance) {
+
+ return balances[tokenOwner];
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Transfer the balance from token owner's account to `to` account
+
+ // - Owner's account must have sufficient balance to transfer
+
+ // - 0 value transfers are allowed
+
+ // ------------------------------------------------------------------------
+
+ function transfer(address to, uint tokens) public returns (bool success) {
+
+ balances[msg.sender] = balances[msg.sender].sub(tokens);
+
+ balances[to] = balances[to].add(tokens);
+
+ emit Transfer(msg.sender, to, tokens);
+
+ return true;
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Token owner can approve for `spender` to transferFrom(...) `tokens`
+
+ // from the token owner's account
+
+ //
+
+ // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
+
+ // recommends that there are no checks for the approval double-spend attack
+
+ // as this should be implemented in user interfaces
+
+ // ------------------------------------------------------------------------
+
+ function approve(address spender, uint tokens) public returns (bool success) {
+
+ allowed[msg.sender][spender] = tokens;
+
+ emit Approval(msg.sender, spender, tokens);
+
+ return true;
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Transfer `tokens` from the `from` account to the `to` account
+
+ //
+
+ // The calling account must already have sufficient tokens approve(...)-d
+
+ // for spending from the `from` account and
+
+ // - From account must have sufficient balance to transfer
+
+ // - Spender must have sufficient allowance to transfer
+
+ // - 0 value transfers are allowed
+
+ // ------------------------------------------------------------------------
+
+ function transferFrom(address from, address to, uint tokens) public returns (bool success) {
+
+ balances[from] = balances[from].sub(tokens);
+
+ allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens);
+
+ balances[to] = balances[to].add(tokens);
+
+ emit Transfer(from, to, tokens);
+
+ return true;
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Returns the amount of tokens approved by the owner that can be
+
+ // transferred to the spender's account
+
+ // ------------------------------------------------------------------------
+
+ function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
+
+ return allowed[tokenOwner][spender];
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Token owner can approve for `spender` to transferFrom(...) `tokens`
+
+ // from the token owner's account. The `spender` contract function
+
+ // `receiveApproval(...)` is then executed
+
+ // ------------------------------------------------------------------------
+
+ function approveAndCall(address spender, uint tokens, bytes memory data) public returns (bool success) {
+
+ allowed[msg.sender][spender] = tokens;
+
+ emit Approval(msg.sender, spender, tokens);
+
+ ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, address(this), data);
+
+ return true;
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Don't accept ETH
+
+ // ------------------------------------------------------------------------
+
+ function () external payable {
+
+ revert();
+
+ }
+
+
+
+ // ------------------------------------------------------------------------
+
+ // Owner can transfer out any accidentally sent ERC20 tokens
+
+ // ------------------------------------------------------------------------
+
+ function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
+
+ return ERC20Interface(tokenAddress).transfer(owner, tokens);
+
+ }
+
+}
\ No newline at end of file
diff --git a/apps/indexer/lib/indexer/block/fetcher.ex b/apps/indexer/lib/indexer/block/fetcher.ex
index 2d4d399eba..1792b941ea 100644
--- a/apps/indexer/lib/indexer/block/fetcher.ex
+++ b/apps/indexer/lib/indexer/block/fetcher.ex
@@ -34,6 +34,7 @@ defmodule Indexer.Block.Fetcher do
alias Indexer.Transform.{
AddressCoinBalances,
+ AddressCoinBalancesDaily,
Addresses,
AddressTokenBalances,
MintTransfers,
@@ -55,6 +56,7 @@ defmodule Indexer.Block.Fetcher do
address_hash_to_fetched_balance_block_number: address_hash_to_fetched_balance_block_number,
addresses: Import.Runner.options(),
address_coin_balances: Import.Runner.options(),
+ address_coin_balances_daily: Import.Runner.options(),
address_token_balances: Import.Runner.options(),
blocks: Import.Runner.options(),
block_second_degree_relations: Import.Runner.options(),
@@ -153,6 +155,14 @@ defmodule Indexer.Block.Fetcher do
transactions_params: transactions_with_receipts
}
|> AddressCoinBalances.params_set(),
+ coin_balances_params_daily_set =
+ %{
+ beneficiary_params: MapSet.to_list(beneficiary_params_set),
+ blocks_params: blocks,
+ logs_params: logs,
+ transactions_params: transactions_with_receipts
+ }
+ |> AddressCoinBalancesDaily.params_set(),
beneficiaries_with_gas_payment <-
beneficiary_params_set
|> add_gas_payments(transactions_with_receipts, blocks)
@@ -164,6 +174,7 @@ defmodule Indexer.Block.Fetcher do
%{
addresses: %{params: addresses},
address_coin_balances: %{params: coin_balances_params_set},
+ address_coin_balances_daily: %{params: coin_balances_params_daily_set},
address_token_balances: %{params: address_token_balances},
blocks: %{params: blocks},
block_second_degree_relations: %{params: block_second_degree_relations_params},
diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex
index 533a79c74c..df4daa5837 100644
--- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex
+++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex
@@ -26,7 +26,7 @@ defmodule Indexer.Block.Realtime.Fetcher do
]
alias Ecto.Changeset
- alias EthereumJSONRPC.{FetchedBalances, Subscription}
+ alias EthereumJSONRPC.{Blocks, FetchedBalances, Subscription}
alias Explorer.Chain
alias Explorer.Chain.Cache.Accounts
alias Explorer.Counters.AverageBlockTime
@@ -172,17 +172,25 @@ defmodule Indexer.Block.Realtime.Fetcher do
block_fetcher,
%{
address_coin_balances: %{params: address_coin_balances_params},
+ address_coin_balances_daily: %{params: address_coin_balances_daily_params},
address_hash_to_fetched_balance_block_number: address_hash_to_block_number,
addresses: %{params: addresses_params},
block_rewards: block_rewards
} = options
) do
- with {:balances, {:ok, %{addresses_params: balances_addresses_params, balances_params: balances_params}}} <-
+ with {:balances,
+ {:ok,
+ %{
+ addresses_params: balances_addresses_params,
+ balances_params: balances_params,
+ balances_daily_params: balances_daily_params
+ }}} <-
{:balances,
balances(block_fetcher, %{
address_hash_to_block_number: address_hash_to_block_number,
addresses_params: addresses_params,
- balances_params: address_coin_balances_params
+ balances_params: address_coin_balances_params,
+ balances_daily_params: address_coin_balances_daily_params
})},
{block_reward_errors, chain_import_block_rewards} = Map.pop(block_rewards, :errors),
chain_import_options =
@@ -191,7 +199,8 @@ defmodule Indexer.Block.Realtime.Fetcher do
|> put_in([:addresses, :params], balances_addresses_params)
|> put_in([:blocks, :params, Access.all(), :consensus], true)
|> put_in([:block_rewards], chain_import_block_rewards)
- |> put_in([Access.key(:address_coin_balances, %{}), :params], balances_params),
+ |> put_in([Access.key(:address_coin_balances, %{}), :params], balances_params)
+ |> put_in([Access.key(:address_coin_balances_daily, %{}), :params], balances_daily_params),
{:import, {:ok, imported} = ok} <- {:import, Chain.import(chain_import_options)} do
async_import_remaining_block_data(
imported,
@@ -381,7 +390,33 @@ defmodule Indexer.Block.Realtime.Fetcher do
importable_balances_params = Enum.map(params_list, &Map.put(&1, :value_fetched_at, value_fetched_at))
- {:ok, %{addresses_params: merged_addresses_params, balances_params: importable_balances_params}}
+ block_numbers =
+ params_list
+ |> Enum.map(&Map.get(&1, :block_number))
+ |> Enum.sort()
+ |> Enum.dedup()
+
+ block_timestamp_map =
+ Enum.reduce(block_numbers, %{}, fn block_number, map ->
+ {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(timestamp)
+ Map.put(map, "#{block_number}", day)
+ end)
+
+ importable_balances_daily_params =
+ Enum.map(params_list, fn param ->
+ day = Map.get(block_timestamp_map, "#{param.block_number}")
+ Map.put(param, :day, day)
+ end)
+
+ {:ok,
+ %{
+ addresses_params: merged_addresses_params,
+ balances_params: importable_balances_params,
+ balances_daily_params: importable_balances_daily_params
+ }}
{:error, _} = error ->
error
diff --git a/apps/indexer/lib/indexer/fetcher/block_reward.ex b/apps/indexer/lib/indexer/fetcher/block_reward.ex
index ed593bb655..7bd933eb5f 100644
--- a/apps/indexer/lib/indexer/fetcher/block_reward.ex
+++ b/apps/indexer/lib/indexer/fetcher/block_reward.ex
@@ -21,7 +21,7 @@ defmodule Indexer.Fetcher.BlockReward do
alias Indexer.{BufferedTask, Tracer}
alias Indexer.Fetcher.BlockReward.Supervisor, as: BlockRewardSupervisor
alias Indexer.Fetcher.CoinBalance
- alias Indexer.Transform.{AddressCoinBalances, Addresses}
+ alias Indexer.Transform.{AddressCoinBalances, AddressCoinBalancesDaily, Addresses}
@behaviour BufferedTask
@@ -245,9 +245,13 @@ defmodule Indexer.Fetcher.BlockReward do
addresses_params = Addresses.extract_addresses(%{block_reward_contract_beneficiaries: block_rewards_params})
address_coin_balances_params_set = AddressCoinBalances.params_set(%{beneficiary_params: block_rewards_params})
+ address_coin_balances_daily_params_set =
+ AddressCoinBalancesDaily.params_set(%{beneficiary_params: block_rewards_params})
+
Chain.import(%{
addresses: %{params: addresses_params},
address_coin_balances: %{params: address_coin_balances_params_set},
+ address_coin_balances_daily: %{params: address_coin_balances_daily_params_set},
block_rewards: %{params: block_rewards_params}
})
end
diff --git a/apps/indexer/lib/indexer/fetcher/coin_balance.ex b/apps/indexer/lib/indexer/fetcher/coin_balance.ex
index f8fadfcb53..5212729c2e 100644
--- a/apps/indexer/lib/indexer/fetcher/coin_balance.ex
+++ b/apps/indexer/lib/indexer/fetcher/coin_balance.ex
@@ -11,7 +11,7 @@ defmodule Indexer.Fetcher.CoinBalance do
import EthereumJSONRPC, only: [integer_to_quantity: 1, quantity_to_integer: 1]
- alias EthereumJSONRPC.FetchedBalances
+ alias EthereumJSONRPC.{Blocks, FetchedBalances}
alias Explorer.Chain
alias Explorer.Chain.{Block, Hash}
alias Explorer.Chain.Cache.Accounts
@@ -77,17 +77,22 @@ defmodule Indexer.Fetcher.CoinBalance do
# `{address, block}`, so take unique params only
unique_entries = Enum.uniq(entries)
- unique_entry_count = Enum.count(unique_entries)
+ unique_filtered_entries =
+ Enum.filter(unique_entries, fn {_hash, block_number} ->
+ block_number >= first_block_to_index()
+ end)
+
+ unique_entry_count = Enum.count(unique_filtered_entries)
Logger.metadata(count: unique_entry_count)
Logger.debug(fn -> "fetching" end)
- unique_entries
+ unique_filtered_entries
|> Enum.map(&entry_to_params/1)
|> EthereumJSONRPC.fetch_balances(json_rpc_named_arguments)
|> case do
{:ok, fetched_balances} ->
- run_fetched_balances(fetched_balances, unique_entries)
+ run_fetched_balances(fetched_balances, unique_filtered_entries)
{:error, reason} ->
Logger.error(
@@ -97,7 +102,16 @@ defmodule Indexer.Fetcher.CoinBalance do
error_count: unique_entry_count
)
- {:retry, unique_entries}
+ {:retry, unique_filtered_entries}
+ end
+ end
+
+ defp first_block_to_index do
+ string_value = Application.get_env(:indexer, :first_block)
+
+ case Integer.parse(string_value) do
+ {integer, ""} -> integer
+ _ -> 0
end
end
@@ -127,11 +141,88 @@ defmodule Indexer.Fetcher.CoinBalance do
importable_balances_params = Enum.map(params_list, &Map.put(&1, :value_fetched_at, value_fetched_at))
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ block_numbers =
+ params_list
+ |> Enum.map(&Map.get(&1, :block_number))
+ |> Enum.sort()
+ |> Enum.dedup()
+
+ block_timestamp_map =
+ Enum.reduce(block_numbers, %{}, fn block_number, map ->
+ {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(timestamp)
+ Map.put(map, "#{block_number}", day)
+ end)
+
+ importable_balances_daily_params =
+ params_list
+ |> Enum.map(fn balance_param ->
+ day = Map.get(block_timestamp_map, "#{balance_param.block_number}")
+
+ incoming_balance_daily_param = %{
+ address_hash: balance_param.address_hash,
+ day: day,
+ value: balance_param.value
+ }
+
+ incoming_balance_daily_param
+ end)
+
addresses_params = balances_params_to_address_params(importable_balances_params)
Chain.import(%{
addresses: %{params: addresses_params, with: :balance_changeset},
address_coin_balances: %{params: importable_balances_params},
+ address_coin_balances_daily: %{params: importable_balances_daily_params},
+ broadcast: broadcast_type
+ })
+ end
+
+ def import_fetched_daily_balances(%FetchedBalances{params_list: params_list}, broadcast_type \\ false) do
+ value_fetched_at = DateTime.utc_now()
+
+ importable_balances_params = Enum.map(params_list, &Map.put(&1, :value_fetched_at, value_fetched_at))
+
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ block_numbers =
+ params_list
+ |> Enum.map(&Map.get(&1, :block_number))
+ |> Enum.sort()
+ |> Enum.dedup()
+
+ block_timestamp_map =
+ Enum.reduce(block_numbers, %{}, fn block_number, map ->
+ {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(timestamp)
+ Map.put(map, "#{block_number}", day)
+ end)
+
+ importable_balances_daily_params =
+ params_list
+ |> Enum.map(fn balance_param ->
+ day = Map.get(block_timestamp_map, "#{balance_param.block_number}")
+
+ incoming_balance_daily_param = %{
+ address_hash: balance_param.address_hash,
+ day: day,
+ value: balance_param.value
+ }
+
+ incoming_balance_daily_param
+ end)
+
+ addresses_params = balances_params_to_address_params(importable_balances_params)
+
+ Chain.import(%{
+ addresses: %{params: addresses_params, with: :balance_changeset},
+ address_coin_balances_daily: %{params: importable_balances_daily_params},
broadcast: broadcast_type
})
end
diff --git a/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex b/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex
index 17014d2ede..3f68f11cb6 100644
--- a/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex
+++ b/apps/indexer/lib/indexer/fetcher/coin_balance_on_demand.ex
@@ -15,10 +15,10 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
import Ecto.Query, only: [from: 2]
import EthereumJSONRPC, only: [integer_to_quantity: 1]
- alias EthereumJSONRPC.FetchedBalances
+ alias EthereumJSONRPC.{FetchedBalances}
alias Explorer.{Chain, Repo}
alias Explorer.Chain.Address
- alias Explorer.Chain.Address.CoinBalance
+ alias Explorer.Chain.Address.{CoinBalance, CoinBalanceDaily}
alias Explorer.Chain.Cache.{Accounts, BlockNumber}
alias Explorer.Counters.AverageBlockTime
alias Indexer.Fetcher.CoinBalance, as: CoinBalanceFetcher
@@ -86,6 +86,12 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
{:noreply, state}
end
+ def handle_cast({:fetch_and_import_daily_balances, block_number, address}, state) do
+ fetch_and_import_daily_balances(block_number, address, state.json_rpc_named_arguments)
+
+ {:noreply, state}
+ end
+
## Implementation
defp do_trigger_fetch(%Address{fetched_coin_balance_block_number: nil} = address, latest_block_number, _) do
@@ -95,6 +101,14 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
end
defp do_trigger_fetch(address, latest_block_number, stale_balance_window) do
+ latest_by_day =
+ from(
+ cbd in CoinBalanceDaily,
+ where: cbd.address_hash == ^address.hash,
+ order_by: [desc: :day],
+ limit: 1
+ )
+
latest =
from(
cb in CoinBalance,
@@ -105,15 +119,28 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
limit: 1
)
+ do_trigger_balance_fetch_query(address, latest_block_number, stale_balance_window, latest, latest_by_day)
+ end
+
+ defp do_trigger_balance_fetch_query(
+ address,
+ latest_block_number,
+ stale_balance_window,
+ query_balances,
+ query_balances_daily
+ ) do
if address.fetched_coin_balance_block_number < stale_balance_window do
+ do_trigger_balance_daily_fetch_query(address, latest_block_number, query_balances_daily)
GenServer.cast(__MODULE__, {:fetch_and_update, latest_block_number, address})
{:stale, latest_block_number}
else
- case Repo.one(latest) do
+ case Repo.one(query_balances) do
nil ->
# There is no recent coin balance to fetch, so we check to see how old the
# balance is on the address. If it is too old, we check again, just to be safe.
+ do_trigger_balance_daily_fetch_query(address, latest_block_number, query_balances_daily)
+
:current
%CoinBalance{value_fetched_at: nil, block_number: block_number} ->
@@ -122,11 +149,19 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
{:pending, block_number}
%CoinBalance{} ->
+ do_trigger_balance_daily_fetch_query(address, latest_block_number, query_balances_daily)
+
:current
end
end
end
+ defp do_trigger_balance_daily_fetch_query(address, latest_block_number, query) do
+ if Repo.one(query) == nil do
+ GenServer.cast(__MODULE__, {:fetch_and_import_daily_balances, latest_block_number, address})
+ end
+ end
+
defp fetch_and_import(block_number, address, json_rpc_named_arguments) do
case fetch_balances(block_number, address, json_rpc_named_arguments) do
{:ok, fetched_balances} -> do_import(fetched_balances)
@@ -134,6 +169,13 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
end
end
+ defp fetch_and_import_daily_balances(block_number, address, json_rpc_named_arguments) do
+ case fetch_balances(block_number, address, json_rpc_named_arguments) do
+ {:ok, fetched_balances} -> do_import_daily_balances(fetched_balances)
+ _ -> :ok
+ end
+ end
+
defp fetch_and_update(block_number, address, json_rpc_named_arguments) do
case fetch_balances(block_number, address, json_rpc_named_arguments) do
{:ok, %{params_list: []}} ->
@@ -165,6 +207,13 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemand do
end
end
+ defp do_import_daily_balances(%FetchedBalances{} = fetched_balances) do
+ case CoinBalanceFetcher.import_fetched_daily_balances(fetched_balances, :on_demand) do
+ {:ok, %{addresses: [address]}} -> {:ok, address}
+ _ -> :error
+ end
+ end
+
defp latest_block_number do
BlockNumber.get_max()
end
diff --git a/apps/indexer/lib/indexer/transform/address_coin_balances_daily.ex b/apps/indexer/lib/indexer/transform/address_coin_balances_daily.ex
new file mode 100644
index 0000000000..8382570ebc
--- /dev/null
+++ b/apps/indexer/lib/indexer/transform/address_coin_balances_daily.ex
@@ -0,0 +1,155 @@
+defmodule Indexer.Transform.AddressCoinBalancesDaily do
+ @moduledoc """
+ Extracts `Explorer.Chain.Address.CoinBalanceDaily` params from other schema's params.
+ """
+
+ alias EthereumJSONRPC.Blocks
+
+ def params_set(%{} = import_options) do
+ Enum.reduce(import_options, MapSet.new(), &reducer/2)
+ end
+
+ defp reducer({:beneficiary_params, beneficiary_params}, acc) when is_list(beneficiary_params) do
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ block_numbers =
+ beneficiary_params
+ |> Enum.map(&Map.get(&1, :block_number))
+ |> Enum.sort()
+ |> Enum.dedup()
+
+ block_timestamp_map =
+ Enum.reduce(block_numbers, %{}, fn block_number, map ->
+ {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(timestamp)
+ Map.put(map, "#{block_number}", day)
+ end)
+
+ Enum.into(beneficiary_params, acc, fn %{
+ address_hash: address_hash,
+ block_number: block_number
+ }
+ when is_binary(address_hash) and is_integer(block_number) ->
+ day = Map.get(block_timestamp_map, "#{block_number}")
+
+ %{address_hash: address_hash, day: day}
+ end)
+ end
+
+ defp reducer({:blocks_params, blocks_params}, acc) when is_list(blocks_params) do
+ # a block MUST have a miner_hash and number
+ Enum.into(blocks_params, acc, fn %{miner_hash: address_hash, number: block_number, timestamp: block_timestamp}
+ when is_binary(address_hash) and is_integer(block_number) ->
+ day = DateTime.to_date(block_timestamp)
+ %{address_hash: address_hash, day: day}
+ end)
+ end
+
+ defp reducer({:internal_transactions_params, internal_transactions_params}, initial)
+ when is_list(internal_transactions_params) do
+ Enum.reduce(internal_transactions_params, initial, &internal_transactions_params_reducer/2)
+ end
+
+ defp reducer({:logs_params, logs_params}, acc) when is_list(logs_params) do
+ # a log MUST have address_hash and block_number
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ block_numbers =
+ logs_params
+ |> Enum.map(&Map.get(&1, :block_number))
+ |> Enum.sort()
+ |> Enum.dedup()
+
+ block_timestamp_map =
+ Enum.reduce(block_numbers, %{}, fn block_number, map ->
+ {:ok, %Blocks{blocks_params: [%{timestamp: timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(timestamp)
+ Map.put(map, "#{block_number}", day)
+ end)
+
+ logs_params
+ |> Enum.into(acc, fn
+ %{address_hash: address_hash, block_number: block_number}
+ when is_binary(address_hash) and is_integer(block_number) ->
+ day = Map.get(block_timestamp_map, "#{block_number}")
+ %{address_hash: address_hash, day: day}
+
+ %{type: "pending"} ->
+ nil
+ end)
+ |> Enum.reject(fn val -> is_nil(val) end)
+ |> MapSet.new()
+ end
+
+ defp reducer({:transactions_params, transactions_params}, initial) when is_list(transactions_params) do
+ Enum.reduce(transactions_params, initial, &transactions_params_reducer/2)
+ end
+
+ defp reducer({:block_second_degree_relations_params, block_second_degree_relations_params}, initial)
+ when is_list(block_second_degree_relations_params),
+ do: initial
+
+ defp internal_transactions_params_reducer(
+ %{block_number: block_number} = internal_transaction_params,
+ acc
+ )
+ when is_integer(block_number) do
+ case internal_transaction_params do
+ %{type: "call"} ->
+ acc
+
+ %{type: "create", error: _} ->
+ acc
+
+ %{type: "create", created_contract_address_hash: address_hash} when is_binary(address_hash) ->
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ {:ok, %Blocks{blocks_params: [%{timestamp: block_timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(block_timestamp)
+ MapSet.put(acc, %{address_hash: address_hash, day: day})
+
+ %{type: "selfdestruct", from_address_hash: from_address_hash, to_address_hash: to_address_hash}
+ when is_binary(from_address_hash) and is_binary(to_address_hash) ->
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ {:ok, %Blocks{blocks_params: [%{timestamp: block_timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(block_timestamp)
+
+ acc
+ |> MapSet.put(%{address_hash: from_address_hash, day: day})
+ |> MapSet.put(%{address_hash: to_address_hash, day: day})
+ end
+ end
+
+ defp transactions_params_reducer(
+ %{block_number: block_number, from_address_hash: from_address_hash} = transaction_params,
+ initial
+ )
+ when is_binary(from_address_hash) do
+ # a transaction MUST have a `from_address_hash`
+ json_rpc_named_arguments = Application.get_env(:explorer, :json_rpc_named_arguments)
+
+ {:ok, %Blocks{blocks_params: [%{timestamp: block_timestamp}]}} =
+ EthereumJSONRPC.fetch_blocks_by_range(block_number..block_number, json_rpc_named_arguments)
+
+ day = DateTime.to_date(block_timestamp)
+ acc = MapSet.put(initial, %{address_hash: from_address_hash, day: day})
+
+ # `to_address_hash` is optional
+ case transaction_params do
+ %{to_address_hash: to_address_hash} when is_binary(to_address_hash) ->
+ MapSet.put(acc, %{address_hash: to_address_hash, day: day})
+
+ _ ->
+ acc
+ end
+ end
+end
diff --git a/apps/indexer/test/indexer/block/fetcher_test.exs b/apps/indexer/test/indexer/block/fetcher_test.exs
index 4bd04dc6dc..f3b1bdd131 100644
--- a/apps/indexer/test/indexer/block/fetcher_test.exs
+++ b/apps/indexer/test/indexer/block/fetcher_test.exs
@@ -79,6 +79,8 @@ defmodule Indexer.Block.FetcherTest do
block_quantity = integer_to_quantity(block_number)
miner_hash = "0x0000000000000000000000000000000000000000"
+ res = eth_block_number_fake_response(block_quantity)
+
case Keyword.fetch!(json_rpc_named_arguments, :variant) do
EthereumJSONRPC.Parity ->
EthereumJSONRPC.Mox
@@ -137,6 +139,17 @@ defmodule Indexer.Block.FetcherTest do
{:ok, [%{id: id, result: []}]}
end
end)
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
EthereumJSONRPC.Geth ->
EthereumJSONRPC.Mox
@@ -381,10 +394,78 @@ defmodule Indexer.Block.FetcherTest do
end)
# async requests need to be grouped in one expect because the order is non-deterministic while multiple expect
# calls on the same name/arity are used in order
- |> expect(:json_rpc, 5, fn json, _options ->
+ |> expect(:json_rpc, 11, fn json, _options ->
[request] = json
case request do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ } ->
+ {:ok,
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
+ "difficulty" => "0xfffffffffffffffffffffffffffffffe",
+ "extraData" => "0xd5830108048650617269747986312e32322e31826c69",
+ "gasLimit" => "0x69fe20",
+ "gasUsed" => "0xc512",
+ "hash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000020000000000000000200000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca",
+ "number" => "0x25",
+ "parentHash" => "0xc37bbad7057945d1bf128c1ff009fb1ad632110bf6a000aac025a80f7766b66e",
+ "receiptsRoot" => "0xd300311aab7dcc98c05ac3f1893629b2c9082c189a0a0c76f4f63e292ac419d5",
+ "sealFields" => [
+ "0x84120a71de",
+ "0xb841fcdb570511ec61edda93849bb7c6b3232af60feb2ea74e4035f0143ab66dfdd00f67eb3eda1adddbb6b572db1e0abd39ce00f9b3ccacb9f47973279ff306fe5401"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "fcdb570511ec61edda93849bb7c6b3232af60feb2ea74e4035f0143ab66dfdd00f67eb3eda1adddbb6b572db1e0abd39ce00f9b3ccacb9f47973279ff306fe5401",
+ "size" => "0x2cf",
+ "stateRoot" => "0x2cd84079b0d0c267ed387e3895fd1c1dc21ff82717beb1132adac64276886e19",
+ "step" => "302674398",
+ "timestamp" => "0x5a343956",
+ "totalDifficulty" => "0x24ffffffffffffffffffffffffedf78dfd",
+ "transactions" => [
+ %{
+ "blockHash" => "0xf6b4b8c88df3ebd252ec476328334dc026cf66606a84fb769b3d3cbccc8471bd",
+ "blockNumber" => "0x25",
+ "chainId" => "0x4d",
+ "condition" => nil,
+ "creates" => nil,
+ "from" => from_address_hash,
+ "gas" => "0x47b760",
+ "gasPrice" => "0x174876e800",
+ "hash" => transaction_hash,
+ "input" => "0x10855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef",
+ "nonce" => "0x4",
+ "publicKey" =>
+ "0xe5d196ad4ceada719d9e592f7166d0c75700f6eab2e3c3de34ba751ea786527cb3f6eb96ad9fdfdb9989ff572df50f1c42ef800af9c5207a38b929aff969b5c9",
+ "r" => "0xa7f8f45cce375bb7af8750416e1b03e0473f93c256da2285d1134fc97a700e01",
+ "raw" =>
+ "0xf88a0485174876e8008347b760948bf38d4764929064f2d4d3a56520a76ab3df415b80a410855269000000000000000000000000862d67cb0773ee3f8ce7ea89b328ffea861ab3ef81bea0a7f8f45cce375bb7af8750416e1b03e0473f93c256da2285d1134fc97a700e01a01f87a076f13824f4be8963e3dffd7300dae64d5f23c9a062af0c6ead347c135f",
+ "s" => "0x1f87a076f13824f4be8963e3dffd7300dae64d5f23c9a062af0c6ead347c135f",
+ "standardV" => "0x1",
+ "to" => to_address_hash,
+ "transactionIndex" => "0x0",
+ "v" => "0xbe",
+ "value" => "0x0"
+ }
+ ],
+ "transactionsRoot" => "0x68e314a05495f390f9cd0c36267159522e5450d2adf254a74567b452e767bf34",
+ "uncles" => []
+ }
+ }
+ ]}
+
%{id: id, method: "eth_getBalance", params: [^to_address_hash, ^block_quantity]} ->
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x1"}]}
@@ -662,6 +743,22 @@ defmodule Indexer.Block.FetcherTest do
}
%{id: id, method: "trace_block"} ->
+ block_quantity = integer_to_quantity(block_number)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
%{
id: id,
result: [
@@ -742,4 +839,40 @@ defmodule Indexer.Block.FetcherTest do
counts.buffer == 0 and counts.tasks == 0
end)
end
+
+ defp eth_block_number_fake_response(block_quantity) do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x0000000000000000000000000000000000000000",
+ "difficulty" => "0x20000",
+ "extraData" => "0x",
+ "gasLimit" => "0x663be0",
+ "gasUsed" => "0x0",
+ "hash" => "0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x0000000000000000000000000000000000000000",
+ "number" => block_quantity,
+ "parentHash" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x80",
+ "0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "size" => "0x215",
+ "stateRoot" => "0xfad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3",
+ "step" => "0",
+ "timestamp" => "0x0",
+ "totalDifficulty" => "0x20000",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ end
end
diff --git a/apps/indexer/test/indexer/block/realtime/fetcher_test.exs b/apps/indexer/test/indexer/block/realtime/fetcher_test.exs
index f222805d26..c4d1e5dc96 100644
--- a/apps/indexer/test/indexer/block/realtime/fetcher_test.exs
+++ b/apps/indexer/test/indexer/block/realtime/fetcher_test.exs
@@ -205,7 +205,7 @@ defmodule Indexer.Block.Realtime.FetcherTest do
}
]}
end)
- |> expect(:json_rpc, 2, fn
+ |> expect(:json_rpc, 5, fn
[
%{id: 0, jsonrpc: "2.0", method: "trace_block", params: ["0x3C365F"]},
%{id: 1, jsonrpc: "2.0", method: "trace_block", params: ["0x3C3660"]}
@@ -217,6 +217,124 @@ defmodule Indexer.Block.Realtime.FetcherTest do
%{id: 1, jsonrpc: "2.0", result: []}
]}
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: ["0x3C365F", true]
+ }
+ ],
+ _ ->
+ {:ok,
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2",
+ "difficulty" => "0xfffffffffffffffffffffffffffffffe",
+ "extraData" => "0xd583010b088650617269747986312e32372e32826c69",
+ "gasLimit" => "0x7a1200",
+ "gasUsed" => "0x2886e",
+ "hash" => "0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cc",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x5ee341ac44d344ade1ca3a771c59b98eb2a77df2",
+ "number" => "0x3c365f",
+ "parentHash" => "0x57f6d66e07488defccd5216c4d2968dd6afd3bd32415e284de3b02af6535e8dc",
+ "receiptsRoot" => "0x111be72e682cea9c93e02f1ef503fb64aa821b2ef510fd9177c49b37d0af98b5",
+ "sealFields" => [
+ "0x841246c63f",
+ "0xb841ba3d11db672fd7893d1b7906275fa7c4c7f4fbcc8fa29eab0331480332361516545ef10a36d800ad2be2b449dde8d5703125156a9cf8a035f5a8623463e051b700"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "ba3d11db672fd7893d1b7906275fa7c4c7f4fbcc8fa29eab0331480332361516545ef10a36d800ad2be2b449dde8d5703125156a9cf8a035f5a8623463e051b700",
+ "size" => "0x33e",
+ "stateRoot" => "0x7f73f5fb9f891213b671356126c31e9795d038844392c7aa8800ed4f52307209",
+ "step" => "306628159",
+ "timestamp" => "0x5b61df3b",
+ "totalDifficulty" => "0x3c365effffffffffffffffffffffffed7f0362",
+ "transactions" => [
+ %{
+ "blockHash" => "0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cc",
+ "blockNumber" => "0x3c365f",
+ "chainId" => "0x63",
+ "condition" => nil,
+ "creates" => nil,
+ "from" => "0x40b18103537c0f15d5e137dd8ddd019b84949d16",
+ "gas" => "0x3d9c5",
+ "gasPrice" => "0x3b9aca00",
+ "hash" => "0xd3937e70fab3fb2bfe8feefac36815408bf07de3b9e09fe81114b9a6b17f55c8",
+ "input" =>
+ "0x8841ac11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005",
+ "nonce" => "0x65b",
+ "publicKey" =>
+ "0x89c2123ed4b5d141cf1f4b6f5f3d754418f03aea2e870a1c50888d94bf5531f74237e2fea72d0bc198ef213272b62c6869615720757255e6cba087f9db6e759f",
+ "r" => "0x55a1a93541d7f782f97f6699437bb60fa4606d63760b30c1ee317e648f93995",
+ "raw" =>
+ "0xf8f582065b843b9aca008303d9c594698bf6943bab687b2756394624aa183f434f65da8901158e4f216242a000b8848841ac11000000000000000000000000000000000000000000000000000000000000006c00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000581eaa0055a1a93541d7f782f97f6699437bb60fa4606d63760b30c1ee317e648f93995a06affd4da5eca84fbca2b016c980f861e0af1f8d6535e2fe29d8f96dc0ce358f7",
+ "s" => "0x6affd4da5eca84fbca2b016c980f861e0af1f8d6535e2fe29d8f96dc0ce358f7",
+ "standardV" => "0x1",
+ "to" => "0x698bf6943bab687b2756394624aa183f434f65da",
+ "transactionIndex" => "0x0",
+ "v" => "0xea",
+ "value" => "0x1158e4f216242a000"
+ }
+ ],
+ "transactionsRoot" => "0xd7c39a93eafe0bdcbd1324c13dcd674bed8c9fa8adbf8f95bf6a59788985da6f",
+ "uncles" => ["0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cd"]
+ }
+ }
+ ]}
+
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: ["0x3C3660", true]
+ }
+ ],
+ _ ->
+ {:ok,
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3",
+ "difficulty" => "0xfffffffffffffffffffffffffffffffe",
+ "extraData" => "0xd583010a068650617269747986312e32362e32826c69",
+ "gasLimit" => "0x7a1200",
+ "gasUsed" => "0x0",
+ "hash" => "0xfb483e511d316fa4072694da3f7abc94b06286406af45061e5e681395bdc6815",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x66c9343c7e8ca673a1fedf9dbf2cd7936dbbf7e3",
+ "number" => "0x3c3660",
+ "parentHash" => "0xa4ec735cabe1510b5ae081b30f17222580b4588dbec52830529753a688b046cc",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x841246c640",
+ "0xb84114db3fd7526b7ea3635f5c85c30dd8a645453aa2f8afe5fd33fe0ec663c9c7b653b0fb5d8dc7d0b809674fa9dca9887d1636a586bf62191da22255eb068bf20800"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "14db3fd7526b7ea3635f5c85c30dd8a645453aa2f8afe5fd33fe0ec663c9c7b653b0fb5d8dc7d0b809674fa9dca9887d1636a586bf62191da22255eb068bf20800",
+ "size" => "0x243",
+ "stateRoot" => "0x3174c461989e9f99e08fa9b4ffb8bce8d9a281c8fc9f80694bb9d3acd4f15559",
+ "step" => "306628160",
+ "timestamp" => "0x5b61df40",
+ "totalDifficulty" => "0x3c365fffffffffffffffffffffffffed7f0360",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ ]}
+
[
%{
id: 0,
diff --git a/apps/indexer/test/indexer/fetcher/block_reward_test.exs b/apps/indexer/test/indexer/fetcher/block_reward_test.exs
index 85d31b6d05..3de7117357 100644
--- a/apps/indexer/test/indexer/fetcher/block_reward_test.exs
+++ b/apps/indexer/test/indexer/fetcher/block_reward_test.exs
@@ -117,6 +117,21 @@ defmodule Indexer.Fetcher.BlockRewardTest do
}
end)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert count(Chain.Block.Reward) == 0
parent = self()
@@ -190,6 +205,21 @@ defmodule Indexer.Fetcher.BlockRewardTest do
}
end)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
parent = self()
pid =
@@ -320,6 +350,21 @@ defmodule Indexer.Fetcher.BlockRewardTest do
}
end)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert count(Chain.Block.Reward) == 0
assert count(Chain.Address.CoinBalance) == 0
@@ -408,6 +453,21 @@ defmodule Indexer.Fetcher.BlockRewardTest do
}
end)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert count(Chain.Block.Reward) == 0
assert count(Chain.Address.CoinBalance) == 0
@@ -486,6 +546,21 @@ defmodule Indexer.Fetcher.BlockRewardTest do
}
end)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert count(Chain.Block.Reward) == 1
assert count(Chain.Address.CoinBalance) == 1
@@ -625,6 +700,21 @@ defmodule Indexer.Fetcher.BlockRewardTest do
}
end)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert count(Chain.Block.Reward) == 0
assert count(Chain.Address.CoinBalance) == 0
@@ -684,4 +774,40 @@ defmodule Indexer.Fetcher.BlockRewardTest do
do_wait_until(parent, ref, producer)
end
end
+
+ defp eth_block_number_fake_response(block_quantity) do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x0000000000000000000000000000000000000000",
+ "difficulty" => "0x20000",
+ "extraData" => "0x",
+ "gasLimit" => "0x663be0",
+ "gasUsed" => "0x0",
+ "hash" => "0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x0000000000000000000000000000000000000000",
+ "number" => block_quantity,
+ "parentHash" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x80",
+ "0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "size" => "0x215",
+ "stateRoot" => "0xfad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3",
+ "step" => "0",
+ "timestamp" => "0x0",
+ "totalDifficulty" => "0x20000",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ end
end
diff --git a/apps/indexer/test/indexer/fetcher/coin_balance_on_demand_test.exs b/apps/indexer/test/indexer/fetcher/coin_balance_on_demand_test.exs
index 8f0ae262e4..bab4f54da2 100644
--- a/apps/indexer/test/indexer/fetcher/coin_balance_on_demand_test.exs
+++ b/apps/indexer/test/indexer/fetcher/coin_balance_on_demand_test.exs
@@ -117,6 +117,21 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemandTest do
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]}
end)
+ res = eth_block_number_fake_response("0x65")
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: ["0x65", true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert CoinBalanceOnDemand.trigger_fetch(address) == {:stale, 101}
{:ok, expected_wei} = Wei.cast(2)
@@ -144,6 +159,20 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemandTest do
{:ok, [%{id: id, jsonrpc: "2.0", result: "0x02"}]}
end)
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, 1, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: ["0x66", true]
+ }
+ ],
+ _ ->
+ res = eth_block_number_fake_response("0x66")
+ {:ok, [res]}
+ end)
+
assert CoinBalanceOnDemand.trigger_fetch(address) == {:pending, 102}
{:ok, expected_wei} = Wei.cast(2)
@@ -154,4 +183,40 @@ defmodule Indexer.Fetcher.CoinBalanceOnDemandTest do
)
end
end
+
+ defp eth_block_number_fake_response(block_quantity) do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x0000000000000000000000000000000000000000",
+ "difficulty" => "0x20000",
+ "extraData" => "0x",
+ "gasLimit" => "0x663be0",
+ "gasUsed" => "0x0",
+ "hash" => "0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x0000000000000000000000000000000000000000",
+ "number" => block_quantity,
+ "parentHash" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x80",
+ "0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "size" => "0x215",
+ "stateRoot" => "0xfad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3",
+ "step" => "0",
+ "timestamp" => "0x0",
+ "totalDifficulty" => "0x20000",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ end
end
diff --git a/apps/indexer/test/indexer/fetcher/coin_balance_test.exs b/apps/indexer/test/indexer/fetcher/coin_balance_test.exs
index 94fbf9f774..12acf46a09 100644
--- a/apps/indexer/test/indexer/fetcher/coin_balance_test.exs
+++ b/apps/indexer/test/indexer/fetcher/coin_balance_test.exs
@@ -58,6 +58,21 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
_options ->
{:ok, [%{id: id, result: integer_to_quantity(fetched_balance)}]}
end)
+
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
end
{:ok, miner_hash} = Hash.Address.cast(miner_hash_data)
@@ -114,6 +129,21 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
_options ->
{:ok, [%{id: id, result: integer_to_quantity(fetched_balance)}]}
end)
+
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
end
{:ok, miner_hash} = Hash.Address.cast(miner_hash_data)
@@ -178,6 +208,21 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
_options ->
{:ok, [%{id: id, result: integer_to_quantity(fetched_balance)}]}
end)
+
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
end
CoinBalance.Supervisor.Case.start_supervised!(json_rpc_named_arguments: json_rpc_named_arguments)
@@ -254,6 +299,25 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
{:ok, %Hash{bytes: address_hash_bytes}} = Hash.Address.cast(hash_data)
entries = Enum.map(block_quantities, &{address_hash_bytes, quantity_to_integer(&1)})
+ res1 = eth_block_number_fake_response("0x1")
+ res2 = eth_block_number_fake_response("0x2")
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{id: 0, jsonrpc: "2.0", method: "eth_getBlockByNumber", params: ["0x1", true]}
+ ],
+ _ ->
+ {:ok, [res1]}
+ end)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{id: 0, jsonrpc: "2.0", method: "eth_getBlockByNumber", params: ["0x2", true]}
+ ],
+ _ ->
+ {:ok, [res2]}
+ end)
+
case CoinBalance.run(entries, json_rpc_named_arguments) do
:ok ->
balances = Repo.all(from(balance in Address.CoinBalance, where: balance.address_hash == ^hash_data))
@@ -314,16 +378,33 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
test "retries none if all imported and no fetch errors", %{json_rpc_named_arguments: json_rpc_named_arguments} do
%Hash{bytes: address_hash_bytes} = address_hash()
- entries = [{address_hash_bytes, block_number()}]
+ block_number = block_number()
+ entries = [{address_hash_bytes, block_number}]
expect(EthereumJSONRPC.Mox, :json_rpc, fn [%{id: id, method: "eth_getBalance", params: [_, _]}], _ ->
{:ok, [%{id: id, result: "0x1"}]}
end)
+ block_quantity = integer_to_quantity(block_number)
+ res = eth_block_number_fake_response(block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^block_quantity, true]
+ }
+ ],
+ _ ->
+ {:ok, [res]}
+ end)
+
assert :ok = CoinBalance.run(entries, json_rpc_named_arguments)
end
- test "retries retries fetch errors if all imported", %{json_rpc_named_arguments: json_rpc_named_arguments} do
+ test "retries fetch errors if all imported", %{json_rpc_named_arguments: json_rpc_named_arguments} do
%Hash{bytes: address_hash_bytes} = address_hash()
bad_block_number = block_number()
good_block_number = block_number()
@@ -359,6 +440,22 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
{:ok, responses}
end)
+ good_block_quantity = integer_to_quantity(good_block_number)
+ res_good = eth_block_number_fake_response(good_block_quantity)
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_getBlockByNumber",
+ params: [^good_block_quantity, true]
+ }
+ ],
+ [] ->
+ {:ok, [res_good]}
+ end)
+
assert {:retry, [{^address_hash_bytes, ^bad_block_number}]} =
CoinBalance.run(
[{address_hash_bytes, good_block_number}, {address_hash_bytes, bad_block_number}],
@@ -374,4 +471,40 @@ defmodule Indexer.Fetcher.CoinBalanceTest do
Process.sleep(100)
wait(producer)
end
+
+ defp eth_block_number_fake_response(block_quantity) do
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: %{
+ "author" => "0x0000000000000000000000000000000000000000",
+ "difficulty" => "0x20000",
+ "extraData" => "0x",
+ "gasLimit" => "0x663be0",
+ "gasUsed" => "0x0",
+ "hash" => "0x5b28c1bfd3a15230c9a46b399cd0f9a6920d432e85381cc6a140b06e8410112f",
+ "logsBloom" =>
+ "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "miner" => "0x0000000000000000000000000000000000000000",
+ "number" => block_quantity,
+ "parentHash" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "receiptsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "sealFields" => [
+ "0x80",
+ "0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ "sha3Uncles" => "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "signature" =>
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "size" => "0x215",
+ "stateRoot" => "0xfad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3",
+ "step" => "0",
+ "timestamp" => "0x0",
+ "totalDifficulty" => "0x20000",
+ "transactions" => [],
+ "transactionsRoot" => "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "uncles" => []
+ }
+ }
+ end
end
diff --git a/mix.lock b/mix.lock
index 8e8b9e3f38..598a6393c8 100644
--- a/mix.lock
+++ b/mix.lock
@@ -32,7 +32,7 @@
"ecto": {:hex, :ecto, "3.3.1", "82ab74298065bf0c64ca299f6c6785e68ea5d6b980883ee80b044499df35aba1", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "e6c614dfe3bcff2d575ce16d815dbd43f4ee1844599a83de1eea81976a31c174"},
"ecto_sql": {:hex, :ecto_sql, "3.3.2", "92804e0de69bb63e621273c3492252cb08a29475c05d40eeb6f41ad2d483cfd3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b82d89d4e6a9f7f7f04783b07e8b0af968e0be2f01ee4b39047fe727c5c07471"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
- "ex_abi": {:git, "https://github.com/poanetwork/ex_abi.git", "ef450816ef4ca98648125577b675ab584251a883", [branch: "master"]},
+ "ex_abi": {:hex, :ex_abi, "0.4.0", "ff7e7f5b56c228b117e1f54e80c668a8f0424c275f233a50373548b70d99bd5c", [:mix], [{:exth_crypto, "~> 0.1.6", [hex: :exth_crypto, repo: "hexpm", optional: false]}], "hexpm", "2d33499de38c54531103e58530d0453863fb6149106327f691001873b0556e68"},
"ex_cldr": {:hex, :ex_cldr, "2.7.2", "d79a1af6ed12630a15175d2b88d4381b22db5d6f835c5da8de132f0cf712b233", [:mix], [{:cldr_utils, "~> 2.1", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "52344684e4e0ff046e1929ae019c0b3c6b122c77c948a43be30684015f2036e2"},
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.3.0", "bffae489416b8b05d4683403263f5d62aae17de70c24ff915a533541fea514de", [:mix], [{:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "7d8ba3738b24d9c7d31bc63b131785b444ed05388fd1cc0958216eb5992d79d6"},
"ex_cldr_lists": {:hex, :ex_cldr_lists, "2.2.0", "b99f8752d098fc6ba5f083bbd0b25d0d01e36b0042155cf6abd5f205306ba849", [:mix], [{:ex_cldr, "~> 2.6", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.6", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "89e25d539a4126472560da2e28b6f1aeb859f5afc0778d6b594029c4226d1775"},
@@ -55,7 +55,7 @@
"gettext": {:hex, :gettext, "0.16.1", "e2130b25eebcbe02bb343b119a07ae2c7e28bd4b146c4a154da2ffb2b3507af2", [:mix], [], "hexpm", "dd3a7ea5e3e87ee9df29452dd9560709b4c7cc8141537d0b070155038d92bdf1"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"},
"html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm", "3e3d7156a272950373ce5a4018b1490bea26676f8d6a7d409f6fac8568b8cb9a"},
- "httpoison": {:hex, :httpoison, "1.0.0", "1f02f827148d945d40b24f0b0a89afe40bfe037171a6cf70f2486976d86921cd", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "07967c56199f716ce9adb27415ccea1bd76c44f777dd0a6d4166c3d932f37fdf"},
+ "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "aa2c74bd271af34239a3948779612f87df2422c2fdcfdbcec28d9c105f0773fe"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"},