From 6f5dc3b5d365b0b0e3c2ce1ade3bed67ea9331aa Mon Sep 17 00:00:00 2001 From: Alexander Kolotov Date: Mon, 29 Apr 2024 12:24:37 +0300 Subject: [PATCH] feat: precompiled contracts ABI import (#9899) * Initial implementation of precompiled contracts ABI import * Documention added * address Sobelow finding * another attempt address Sobelow finding * Apply evident suggestions from code review Co-authored-by: Kirill Fedoseev * Fix afer merge * Small inconsistency in spec * different path for different mix environment * fix for formatting issue --------- Co-authored-by: Kirill Fedoseev --- .../lib/explorer/chain/smart_contract.ex | 89 +++++-- .../lib/explorer/chain_spec/genesis_data.ex | 247 ++++++++++++++++-- .../lib/explorer/chain_spec/geth/importer.ex | 60 ++++- .../smart_contract/solidity/publisher.ex | 30 ++- config/assets/precompiles-arbitrum.json | 130 +++++++++ config/runtime.exs | 15 +- docker/Dockerfile | 1 + 7 files changed, 529 insertions(+), 43 deletions(-) create mode 100644 config/assets/precompiles-arbitrum.json diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex index c29d9f7363..7ea65c1688 100644 --- a/apps/explorer/lib/explorer/chain/smart_contract.ex +++ b/apps/explorer/lib/explorer/chain/smart_contract.ex @@ -861,24 +861,39 @@ defmodule Explorer.Chain.SmartContract do end @doc """ - Inserts a `t:SmartContract.t/0`. + Inserts a new smart contract and associated data into the database. - As part of inserting a new smart contract, an additional record is inserted for - naming the address for reference. + This function creates a new smart contract entry in the database. It calculates an MD5 hash of + the contract's bytecode, upserts contract methods, and handles the linkage of external libraries and + additional secondary sources. It also updates the associated address to mark the contract as + verified and manages the naming records for the address. + + ## Parameters + - `attrs`: Attributes for the new smart contract. + - `external_libraries`: A list of external libraries used by the contract. + - `secondary_sources`: Additional source data related to the contract. + + ## Returns + - `{:ok, smart_contract}` on successful insertion. + - `{:error, data}` on failure, returning the changeset or, if any issues happen during setting the address as verified, an error message. """ @spec create_smart_contract(map(), list(), list()) :: {:ok, __MODULE__.t()} | {:error, Ecto.Changeset.t()} def create_smart_contract(attrs \\ %{}, external_libraries \\ [], secondary_sources \\ []) do new_contract = %__MODULE__{} + # Updates contract attributes with calculated MD5 for the contract's bytecode attrs = attrs |> Helper.add_contract_code_md5() + # Prepares changeset and extends it with external libraries. + # As part of changeset preparation and verification, contract methods are upserted smart_contract_changeset = new_contract |> __MODULE__.changeset(attrs) |> Changeset.put_change(:external_libraries, external_libraries) + # Prepares changesets for additional sources associated with the contract new_contract_additional_source = %SmartContractAdditionalSource{} smart_contract_additional_sources_changesets = @@ -894,7 +909,10 @@ defmodule Explorer.Chain.SmartContract do address_hash = Changeset.get_field(smart_contract_changeset, :address_hash) - # Enforce ShareLocks tables order (see docs: sharelocks.md) + # Prepares the queries to update Explorer.Chain.Address to mark the contract as + # verified, clear the primary flag for the contract address in + # Explorer.Chain.Address.Name if any (enforce ShareLocks tables order (see + # docs: sharelocks.md)) and insert the contract details. insert_contract_query = Multi.new() |> Multi.run(:set_address_verified, fn repo, _ -> set_address_verified(repo, address_hash) end) @@ -903,6 +921,8 @@ defmodule Explorer.Chain.SmartContract do end) |> Multi.insert(:smart_contract, smart_contract_changeset) + # Updates the queries from the previous step with inserting additional sources + # of the contract insert_contract_query_with_additional_sources = smart_contract_additional_sources_changesets |> Enum.with_index() @@ -910,10 +930,12 @@ defmodule Explorer.Chain.SmartContract do Multi.insert(multi, "smart_contract_additional_source_#{Integer.to_string(index)}", changeset) end) + # Applying the queries to the database insert_result = insert_contract_query_with_additional_sources |> Repo.transaction() + # Set the primary mark for the contract name AddressName.create_primary_address_name(Repo, Changeset.get_field(smart_contract_changeset, :name), address_hash) case insert_result do @@ -929,16 +951,28 @@ defmodule Explorer.Chain.SmartContract do end @doc """ - Updates a `t:SmartContract.t/0`. - - Has the similar logic as create_smart_contract/1. - Used in cases when you need to update row in DB contains SmartContract, e.g. in case of changing - status `partially verified` to `fully verified` (re-verify). + Updates an existing smart contract and associated data into the database. + + This function is similar to `create_smart_contract/1` but is used for updating an existing smart + contract, such as changing its verification status from `partially verified` to `fully verified`. + It handles the updates including external libraries and secondary sources associated with the contract. + Notably, it updates contract methods based on the new ABI provided: if the new ABI does not contain + some of the previously listed methods, those methods are retained in the database. + + ## Parameters + - `attrs`: Attributes for the smart contract to be updated. + - `external_libraries`: A list of external libraries associated with the contract. + - `secondary_sources`: A list of secondary source data associated with the contract. + + ## Returns + - `{:ok, smart_contract}` on successful update. + - `{:error, changeset}` on failure, indicating issues with the data provided for update. """ @spec update_smart_contract(map(), list(), list()) :: {:ok, __MODULE__.t()} | {:error, Ecto.Changeset.t()} def update_smart_contract(attrs \\ %{}, external_libraries \\ [], secondary_sources \\ []) do address_hash = Map.get(attrs, :address_hash) + # Removes all additional sources associated with the contract query_sources = from( source in SmartContractAdditionalSource, @@ -947,14 +981,20 @@ defmodule Explorer.Chain.SmartContract do _delete_sources = Repo.delete_all(query_sources) + # Retrieve the existing smart contract query = get_smart_contract_query(address_hash) smart_contract = Repo.one(query) + # Updates existing changeset and extends it with external libraries. + # As part of changeset preparation and verification, contract methods are + # updated as so if new ABI does not contain some of previous methods, they + # are still kept in the database smart_contract_changeset = smart_contract |> __MODULE__.changeset(attrs) |> Changeset.put_change(:external_libraries, external_libraries) + # Prepares changesets for additional sources associated with the contract new_contract_additional_source = %SmartContractAdditionalSource{} smart_contract_additional_sources_changesets = @@ -968,7 +1008,9 @@ defmodule Explorer.Chain.SmartContract do [] end - # Enforce ShareLocks tables order (see docs: sharelocks.md) + # Prepares the queries to clear the primary flag for the contract address in + # Explorer.Chain.Address.Name if any (enforce ShareLocks tables order (see + # docs: sharelocks.md)) and updated the contract details. insert_contract_query = Multi.new() |> Multi.run(:clear_primary_address_names, fn repo, _ -> @@ -976,6 +1018,8 @@ defmodule Explorer.Chain.SmartContract do end) |> Multi.update(:smart_contract, smart_contract_changeset) + # Updates the queries from the previous step with inserting additional sources + # of the contract insert_contract_query_with_additional_sources = smart_contract_additional_sources_changesets |> Enum.with_index() @@ -983,10 +1027,12 @@ defmodule Explorer.Chain.SmartContract do Multi.insert(multi, "smart_contract_additional_source_#{Integer.to_string(index)}", changeset) end) + # Applying the queries to the database insert_result = insert_contract_query_with_additional_sources |> Repo.transaction() + # Set the primary mark for the contract name AddressName.create_primary_address_name(Repo, Changeset.get_field(smart_contract_changeset, :name), address_hash) case insert_result do @@ -995,9 +1041,6 @@ defmodule Explorer.Chain.SmartContract do {:error, :smart_contract, changeset, _} -> {:error, changeset} - - {:error, :set_address_verified, message, _} -> - {:error, message} end end @@ -1059,10 +1102,14 @@ defmodule Explorer.Chain.SmartContract do end @doc """ - Checks if it exists a verified `t:Explorer.Chain.SmartContract.t/0` for the - `t:Explorer.Chain.Address.t/0` with the provided `hash`. + Checks if a `Explorer.Chain.SmartContract` exists for the provided address hash. - Returns `true` if found and `false` otherwise. + ## Parameters + - `address_hash_str` or `address_hash`: The hash of the address in binary string + form or directly as an address hash. + + ## Returns + - `boolean()`: `true` if a smart contract exists, `false` otherwise. """ @spec verified?(Hash.Address.t() | String.t()) :: boolean() def verified?(address_hash_str) when is_binary(address_hash_str) do @@ -1118,7 +1165,13 @@ defmodule Explorer.Chain.SmartContract do end @doc """ - Gets smart-contract by address hash + Composes a query for fetching a smart contract by its address hash. + + ## Parameters + - `address_hash`: The hash of the smart contract's address. + + ## Returns + - An `Ecto.Query.t()` that represents the query to fetch the smart contract. """ @spec get_smart_contract_query(Hash.Address.t() | binary) :: Ecto.Query.t() def get_smart_contract_query(address_hash) do @@ -1263,6 +1316,8 @@ defmodule Explorer.Chain.SmartContract do end end + # Checks if a smart contract exists in `Explorer.Chain.SmartContract` for a given + # address hash. @spec verified_smart_contract_exists?(Hash.Address.t()) :: boolean() defp verified_smart_contract_exists?(address_hash) do query = get_smart_contract_query(address_hash) diff --git a/apps/explorer/lib/explorer/chain_spec/genesis_data.ex b/apps/explorer/lib/explorer/chain_spec/genesis_data.ex index 764ca7c69a..71be060928 100644 --- a/apps/explorer/lib/explorer/chain_spec/genesis_data.ex +++ b/apps/explorer/lib/explorer/chain_spec/genesis_data.ex @@ -1,6 +1,10 @@ defmodule Explorer.ChainSpec.GenesisData do @moduledoc """ - Fetches genesis data. + Handles the genesis data import. + + This module is responsible for managing the import of genesis data into the + database, which includes pre-mined balances and precompiled smart contract + bytecodes. """ use GenServer @@ -10,6 +14,7 @@ defmodule Explorer.ChainSpec.GenesisData do alias Explorer.ChainSpec.Geth.Importer, as: GethImporter alias Explorer.ChainSpec.Parity.Importer alias Explorer.Helper + alias Explorer.SmartContract.Solidity.Publisher, as: SolidityPublisher alias HTTPoison.Response @interval :timer.minutes(2) @@ -28,13 +33,23 @@ defmodule Explorer.ChainSpec.GenesisData do # Callback for errored fetch @impl GenServer def handle_info({_ref, {:error, reason}}, state) do - Logger.warn(fn -> "Failed to fetch genesis data '#{reason}'." end) + Logger.warn(fn -> "Failed to fetch and import genesis data or precompiled contracts: '#{reason}'." end) fetch_genesis_data() {:noreply, state} end + # Initiates the import of genesis data. + # + # This function triggers the fetching and importing of genesis data, including pre-mined balances and precompiled smart contract bytecodes. + # + # ## Parameters + # - `:import`: The message that triggers this function. + # - `state`: The current state of the GenServer. + # + # ## Returns + # - `{:noreply, state}` @impl GenServer def handle_info(:import, state) do Logger.debug(fn -> "Importing genesis data" end) @@ -57,39 +72,87 @@ defmodule Explorer.ChainSpec.GenesisData do end @doc """ - Fetches pre-mined balances and pre-compiled smart-contract bytecodes from genesis.json + Fetches and processes the genesis data, which includes pre-mined balances and precompiled smart contract bytecodes. + + This function retrieves the chain specification and precompiled contracts + configuration from specified paths in the application settings. Then it + asynchronously extends the chain spec with precompiled contracts, imports + genesis accounts, and the precompiled contracts' sources and ABIs. + + ## Returns + - `Task.t()`: A task handle if the fetch and processing are scheduled successfully. + - `:ok`: Indicates no fetch was attempted due to missing configuration paths. """ @spec fetch_genesis_data() :: Task.t() | :ok def fetch_genesis_data do - path = Application.get_env(:explorer, __MODULE__)[:chain_spec_path] + chain_spec_path = get_path(:chain_spec_path) + precompiled_config_path = get_path(:precompiled_config_path) - if path do + if is_nil(chain_spec_path) and is_nil(precompiled_config_path) do + Logger.warn(fn -> "Genesis data is not fetched. Neither chain spec path or precompiles config path are set." end) + else json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments) variant = Keyword.fetch!(json_rpc_named_arguments, :variant) Task.Supervisor.async_nolink(Explorer.GenesisDataTaskSupervisor, fn -> - case fetch_spec(path) do - {:ok, chain_spec} -> - case variant do - EthereumJSONRPC.Geth -> - {:ok, _} = GethImporter.import_genesis_accounts(chain_spec) - - _ -> - Importer.import_emission_rewards(chain_spec) - {:ok, _} = Importer.import_genesis_accounts(chain_spec) - end - - {:error, reason} -> - # credo:disable-for-next-line - Logger.warn(fn -> "Failed to fetch genesis data. #{inspect(reason)}" end) - end + chain_spec = fetch_chain_spec(chain_spec_path) + precompiles_config = fetch_precompiles_config(precompiled_config_path) + + extended_chain_spec = extend_chain_spec(chain_spec, precompiles_config, variant) + import_genesis_accounts(extended_chain_spec, variant) + + import_precompiles_sources_and_abi(precompiles_config) end) + end + end + + @spec get_path(atom()) :: nil | binary() + defp get_path(key) do + case Application.get_env(:explorer, __MODULE__)[key] do + nil -> nil + value when is_binary(value) -> value + end + end + + # Retrieves the chain specification, returning an empty map if unsuccessful. + @spec fetch_chain_spec(binary() | nil) :: map() | list() + defp fetch_chain_spec(path) do + case do_fetch(path, "Failed to fetch chain spec.") do + nil -> %{} + value -> value + end + end + + # Retrieves the precompiled contracts configuration, returning an empty list if unsuccessful. + @spec fetch_precompiles_config(binary() | nil) :: list() + defp fetch_precompiles_config(path) do + case do_fetch(path, "Failed to fetch precompiles config.") do + nil -> [] + value -> value + end + end + + # Fetches JSON data from a specified path. + @spec do_fetch(binary() | nil, binary()) :: list() | map() | nil + defp do_fetch(path, warn_message_prefix) do + if path do + case fetch_spec_as_json(path) do + {:ok, chain_spec} -> + chain_spec + + {:error, reason} -> + # credo:disable-for-next-line Credo.Check.Refactor.Nesting + Logger.warn(fn -> "#{warn_message_prefix} #{inspect(reason)}" end) + nil + end else - Logger.warn(fn -> "Failed to fetch genesis data. Chain spec path is not set." end) + nil end end - defp fetch_spec(path) do + # Retrieves a JSON data from either a file or URL based on the source. + @spec fetch_spec_as_json(binary()) :: {:ok, list() | map()} | {:error, any()} + defp fetch_spec_as_json(path) do if Helper.valid_url?(path) do fetch_from_url(path) else @@ -97,6 +160,8 @@ defmodule Explorer.ChainSpec.GenesisData do end end + # Reads and parses JSON data from a file. + @spec fetch_from_file(binary()) :: {:ok, list() | map()} | {:error, Jason.DecodeError.t()} # sobelow_skip ["Traversal"] defp fetch_from_file(path) do with {:ok, data} <- File.read(path) do @@ -104,6 +169,8 @@ defmodule Explorer.ChainSpec.GenesisData do end end + # Fetches JSON data from a provided URL. + @spec fetch_from_url(binary()) :: {:ok, list() | map()} | {:error, Jason.DecodeError.t() | HTTPoison.Error.t()} defp fetch_from_url(url) do case HTTPoison.get(url) do {:ok, %Response{body: body, status_code: 200}} -> @@ -113,4 +180,140 @@ defmodule Explorer.ChainSpec.GenesisData do {:error, reason} end end + + # Extends the chain specification with precompiled contract information. + # + # This function modifies the chain specification to include precompiled + # contracts that are not originally listed in the spec. It handles different + # formats of chain specs (list or map) according to the `variant` specified + # and adds precompiles. + # + # ## Parameters + # - `chain_spec`: The original chain specification in map or list format. + # - `precompiles_config`: A list of precompiled contracts to be added. + # - `variant`: The client variant (e.g., Geth or Parity), which dictates the + # spec structure. + # + # ## Returns + # - The modified chain specification with precompiled contracts included. + @spec extend_chain_spec(map() | list(), list(), EthereumJSONRPC.Geth | EthereumJSONRPC.Parity) :: map() | list() + defp extend_chain_spec(chain_spec, [], _) do + chain_spec + end + + # Resulting spec will be handled by Explorer.ChainSpec.Geth.Importer + defp extend_chain_spec(chain_spec, precompiles_config, variant) + when is_list(chain_spec) and variant == EthereumJSONRPC.Geth do + precompiles_as_map = + precompiles_config + |> Enum.reduce(%{}, fn contract, acc -> + Map.put(acc, contract["address"], %{ + "address" => contract["address"], + "balance" => 0, + "bytecode" => contract["bytecode"] + }) + end) + + filtered_maps_of_precompiles = + chain_spec + |> Enum.reduce(precompiles_as_map, fn account, acc -> + Map.delete(acc, account["address"]) + end) + + chain_spec ++ Map.values(filtered_maps_of_precompiles) + end + + # Resulting spec will be handled by Explorer.ChainSpec.Geth.Importer + defp extend_chain_spec(%{"genesis" => sub_entity} = chain_spec, precompiles_config, variant) + when variant == EthereumJSONRPC.Geth do + updated_sub_entity = extend_chain_spec(sub_entity, precompiles_config, variant) + + Map.put(chain_spec, "genesis", updated_sub_entity) + end + + # Resulting spec will be handled by Explorer.ChainSpec.Geth.Importer + defp extend_chain_spec(chain_spec, precompiles_config, variant) + when is_map(chain_spec) and variant == EthereumJSONRPC.Geth do + accounts = + case chain_spec["alloc"] do + nil -> %{} + value -> value + end + + updated_accounts = + precompiles_config + |> Enum.reduce(accounts, fn contract, acc -> + Map.put_new(acc, contract["address"], %{"balance" => 0, "code" => contract["bytecode"]}) + end) + + Map.put(chain_spec, "alloc", updated_accounts) + end + + # Resulting spec will be handled by Explorer.ChainSpec.Parity.Importer + defp extend_chain_spec(chain_spec, precompiles_config, _) when is_map(chain_spec) do + accounts = + case chain_spec["accounts"] do + nil -> %{} + value -> value + end + + updated_accounts = + precompiles_config + |> Enum.reduce(accounts, fn contract, acc -> + Map.put_new(acc, contract["address"], %{"balance" => 0, "constructor" => contract["bytecode"]}) + end) + + Map.put(chain_spec, "accounts", updated_accounts) + end + + # Imports genesis accounts from the specified chain specification and updates + # `Explorer.Chain.Address` and `Explorer.Chain.Address.CoinBalance`, and + # `Explorer.Chain.Address.CoinBalanceDaily`. + @spec import_genesis_accounts(map() | list(), EthereumJSONRPC.Geth | EthereumJSONRPC.Parity) :: any() + defp import_genesis_accounts(chain_spec, variant) do + if not Enum.empty?(chain_spec) do + case variant do + EthereumJSONRPC.Geth -> + {:ok, _} = GethImporter.import_genesis_accounts(chain_spec) + + _ -> + Importer.import_emission_rewards(chain_spec) + {:ok, _} = Importer.import_genesis_accounts(chain_spec) + end + end + end + + # Iterates through the list of precompiles descriptions, and creating/updating + # each smart contract. + @spec import_precompiles_sources_and_abi([map()]) :: any() + defp import_precompiles_sources_and_abi(precompiles_config) do + precompiles_config + |> Enum.each(fn contract -> + attrs = %{ + address_hash: contract["address"], + name: contract["name"], + file_path: nil, + compiler_version: contract["compiler"], + evm_version: nil, + optimization_runs: nil, + optimization: false, + contract_source_code: contract["source"], + constructor_arguments: nil, + external_libraries: [], + secondary_sources: [], + abi: Jason.decode!(contract["abi"]), + verified_via_sourcify: false, + verified_via_eth_bytecode_db: false, + verified_via_verifier_alliance: false, + partially_verified: false, + is_vyper_contract: false, + autodetect_constructor_args: nil, + is_yul: false, + compiler_settings: nil, + license_type: :none + } + + SolidityPublisher.create_or_update_smart_contract(contract["address"], attrs) + end) + end end diff --git a/apps/explorer/lib/explorer/chain_spec/geth/importer.ex b/apps/explorer/lib/explorer/chain_spec/geth/importer.ex index 40db5445a8..bc2dd89f66 100644 --- a/apps/explorer/lib/explorer/chain_spec/geth/importer.ex +++ b/apps/explorer/lib/explorer/chain_spec/geth/importer.ex @@ -1,4 +1,3 @@ -# credo:disable-for-this-file defmodule Explorer.ChainSpec.Geth.Importer do @moduledoc """ Imports data from Geth genesis.json. @@ -10,7 +9,28 @@ defmodule Explorer.ChainSpec.Geth.Importer do alias Explorer.{Chain, Helper} alias Explorer.Chain.Hash.Address + @doc """ + Imports genesis accounts into the database from a chain specification. + + This function extracts genesis account information from a given chain specification, + including initial balances and contract bytecode. It enriches this data with additional + metadata, such as setting the block number to 0 (for genesis accounts) and determining + the day based on the timestamp of the first block. Subsequently, it imports the data + into `Explorer.Chain.Address`, `Explorer.Chain.Address.CoinBalance`, and + `Explorer.Chain.Address.CoinBalanceDaily` tables. + + ## Parameters + - `chain_spec`: A map or list representing the chain specification that contains + genesis account information. It may be structured directly as an + account list or as part of a larger specification map. + + ## Returns + - N/A + """ + @spec import_genesis_accounts(map() | list()) :: any() def import_genesis_accounts(chain_spec) do + # credo:disable-for-previous-line Credo.Check.Design.DuplicatedCode + # It duplicates `import_genesis_accounts/1` from `Explorer.ChainSpec.Parity.Importer` balance_params = chain_spec |> genesis_accounts() @@ -50,7 +70,32 @@ defmodule Explorer.ChainSpec.Geth.Importer do Chain.import(params) end - @spec genesis_accounts(any()) :: [%{address_hash: Address.t(), value: integer(), contract_code: String.t()}] + @doc """ + Parses and returns the genesis account information from a chain specification. + + It extracts account data such as address hashes, initial balances, and + optionally, contract bytecode for accounts defined in the genesis block of + a blockchain configuration. + + ## Parameters + - `input`: Can be a list of account maps or a map of the entire chain specification. + + ## Returns + - A list of maps, each representing an account with keys for the address hash, + balance , and optionally, the contract bytecode. Accounts without defined + balances are omitted. + + ### Usage + - `genesis_accounts(%{"genesis" => genesis_data})`: Extracts accounts from + a nested genesis key. + - `genesis_accounts(chain_spec)`: Parses accounts from a chain specification that + includes an 'alloc' key. + - `genesis_accounts(list_of_accounts)`: Directly parses a list of account data. + Intended to be called after `genesis_accounts(%{"genesis" => genesis_data})` call. + """ + @spec genesis_accounts(map() | list()) :: [ + %{address_hash: Address.t(), value: non_neg_integer(), contract_code: String.t()} + ] def genesis_accounts(%{"genesis" => genesis}) do genesis_accounts(genesis) end @@ -80,6 +125,17 @@ defmodule Explorer.ChainSpec.Geth.Importer do end end + # Parses account data from a provided map to extract address, balance, and optional contract code. + # + # ## Parameters + # - `accounts`: A map with accounts data. + # + # ## Returns + # - A list of maps with accounts data including address hashes, balances, + # and any associated contract code. + @spec parse_accounts(%{binary() => map()}) :: [ + %{:address_hash => Address.t(), value: non_neg_integer(), contract_code: String.t() | nil} + ] defp parse_accounts(accounts) do accounts |> Stream.filter(fn {_address, map} -> diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex index c02d64390b..f0f6d0c8ed 100644 --- a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex +++ b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex @@ -199,7 +199,35 @@ defmodule Explorer.SmartContract.Solidity.Publisher do create_or_update_smart_contract(address_hash, attrs) end - defp create_or_update_smart_contract(address_hash, attrs) do + @doc """ + Creates or updates a smart contract record based on its verification status. + + This function first checks if a smart contract associated with the provided address hash + is already verified. If verified, it updates the existing smart contract record with the + new attributes provided, such as external libraries and secondary sources. During the update, + the contract methods are also updated: existing methods are preserved, and any new methods + from the provided ABI are added to ensure the contract's integrity and completeness. + + If the smart contract is not verified, it creates a new record in the database with the + provided attributes, setting it up for verification. In this case, all contract methods + from the ABI are freshly inserted as part of the new smart contract creation. + + ## Parameters + - `address_hash`: The hash of the address for the smart contract. + - `attrs`: A map containing attributes such as external libraries and secondary sources. + + ## Returns + - `{:ok, Explorer.Chain.SmartContract.t()}`: Successfully created or updated smart + contract. + - `{:error, data}`: on failure, returning `Ecto.Changeset.t()` or, if any issues + happen during setting the address as verified, an error message. + """ + @spec create_or_update_smart_contract(binary() | Explorer.Chain.Hash.t(), %{ + :external_libraries => list(), + :secondary_sources => list(), + optional(any()) => any() + }) :: {:error, Ecto.Changeset.t() | String.t()} | {:ok, Explorer.Chain.SmartContract.t()} + def create_or_update_smart_contract(address_hash, attrs) do Logger.info("Publish successfully verified Solidity smart-contract #{address_hash} into the DB") if SmartContract.verified?(address_hash) do diff --git a/config/assets/precompiles-arbitrum.json b/config/assets/precompiles-arbitrum.json new file mode 100644 index 0000000000..4dcfac003e --- /dev/null +++ b/config/assets/precompiles-arbitrum.json @@ -0,0 +1,130 @@ +[ + { + "address": "0x00000000000000000000000000000000000a4b05", + "name": "ArbOS", + "bytecode": "0xfe", + "compiler": "EVM Hypervisor (go 1.17)", + "source": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * Copyright 2020, Offchain Labs, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npragma solidity >=0.4.21 <0.9.0;\n\n/**\n * @title This precompile represents ArbOS's internal actions as calls it makes to itself\n * @notice Calling this precompile will always revert and should not be done.\n */\ninterface ArbosActs {\n /**\n * @notice ArbOS \"calls\" this when starting a block\n * @param l1BaseFee the L1 BaseFee\n * @param l1BlockNumber the L1 block number\n * @param timePassed number of seconds since the last block\n */\n function startBlock(\n uint256 l1BaseFee,\n uint64 l1BlockNumber,\n uint64 l2BlockNumber,\n uint64 timePassed\n ) external;\n\n function batchPostingReport(\n uint256 batchTimestamp,\n address batchPosterAddress,\n uint64 batchNumber,\n uint64 batchDataGas,\n uint256 l1BaseFeeWei\n ) external;\n\n error CallerNotArbOS();\n}\n", + "abi": "[{\"inputs\":[],\"name\":\"CallerNotArbOS\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"batchPosterAddress\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"batchNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"batchDataGas\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"l1BaseFeeWei\",\"type\":\"uint256\"}],\"name\":\"batchPostingReport\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"l1BaseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"l1BlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"l2BlockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timePassed\",\"type\":\"uint64\"}],\"name\":\"startBlock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]\n" + }, + { + "address": "0x0000000000000000000000000000000000000064", + "name": "ArbSys", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/**\n * @title System level functionality\n * @notice For use by contracts to interact with core L2-specific functionality.\n * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064.\n */\ninterface ArbSys {\n /**\n * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)\n * @return block number as int\n */\n function arbBlockNumber() external view returns (uint256);\n\n /**\n * @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum)\n * @return block hash\n */\n function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32);\n\n /**\n * @notice Gets the rollup's unique chain identifier\n * @return Chain identifier as int\n */\n function arbChainID() external view returns (uint256);\n\n /**\n * @notice Get internal version number identifying an ArbOS build\n * @return version number as int\n */\n function arbOSVersion() external view returns (uint256);\n\n /**\n * @notice Returns 0 since Nitro has no concept of storage gas\n * @return uint 0\n */\n function getStorageGasAvailable() external view returns (uint256);\n\n /**\n * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract)\n * @dev this call has been deprecated and may be removed in a future release\n * @return true if current execution frame is not a call by another L2 contract\n */\n function isTopLevelCall() external view returns (bool);\n\n /**\n * @notice map L1 sender contract address to its L2 alias\n * @param sender sender address\n * @param unused argument no longer used\n * @return aliased sender address\n */\n function mapL1SenderContractAddressToL2Alias(address sender, address unused)\n external\n pure\n returns (address);\n\n /**\n * @notice check if the caller (of this caller of this) is an aliased L1 contract address\n * @return true iff the caller's address is an alias for an L1 contract address\n */\n function wasMyCallersAddressAliased() external view returns (bool);\n\n /**\n * @notice return the address of the caller (of this caller of this), without applying L1 contract address aliasing\n * @return address of the caller's caller, without applying L1 contract address aliasing\n */\n function myCallersAddressWithoutAliasing() external view returns (address);\n\n /**\n * @notice Send given amount of Eth to dest from sender.\n * This is a convenience function, which is equivalent to calling sendTxToL1 with empty data.\n * @param destination recipient address on L1\n * @return unique identifier for this L2-to-L1 transaction.\n */\n function withdrawEth(address destination) external payable returns (uint256);\n\n /**\n * @notice Send a transaction to L1\n * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data\n * to a contract address without any code (as enforced by the Bridge contract).\n * @param destination recipient address on L1\n * @param data (optional) calldata for L1 contract call\n * @return a unique identifier for this L2-to-L1 transaction.\n */\n function sendTxToL1(address destination, bytes calldata data)\n external\n payable\n returns (uint256);\n\n /**\n * @notice Get send Merkle tree state\n * @return size number of sends in the history\n * @return root root hash of the send history\n * @return partials hashes of partial subtrees in the send history tree\n */\n function sendMerkleTreeState()\n external\n view\n returns (\n uint256 size,\n bytes32 root,\n bytes32[] memory partials\n );\n\n /**\n * @notice creates a send txn from L2 to L1\n * @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf\n */\n event L2ToL1Tx(\n address caller,\n address indexed destination,\n uint256 indexed hash,\n uint256 indexed position,\n uint256 arbBlockNum,\n uint256 ethBlockNum,\n uint256 timestamp,\n uint256 callvalue,\n bytes data\n );\n\n /// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade\n event L2ToL1Transaction(\n address caller,\n address indexed destination,\n uint256 indexed uniqueId,\n uint256 indexed batchNumber,\n uint256 indexInBatch,\n uint256 arbBlockNum,\n uint256 ethBlockNum,\n uint256 timestamp,\n uint256 callvalue,\n bytes data\n );\n\n /**\n * @notice logs a merkle branch for proof synthesis\n * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event\n * @param hash the merkle hash\n * @param position = (level << 192) + leaf\n */\n event SendMerkleUpdate(\n uint256 indexed reserved,\n bytes32 indexed hash,\n uint256 indexed position\n );\n\n error InvalidBlockNumber(uint256 requested, uint256 current);\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"current\",\"type\":\"uint256\"}],\"name\":\"InvalidBlockNumber\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"uniqueId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"indexInBatch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"arbBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ethBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callvalue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"L2ToL1Transaction\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hash\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"position\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"arbBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ethBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callvalue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"L2ToL1Tx\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"reserved\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"position\",\"type\":\"uint256\"}],\"name\":\"SendMerkleUpdate\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"arbBlockNum\",\"type\":\"uint256\"}],\"name\":\"arbBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"arbBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"arbChainID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"arbOSVersion\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStorageGasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isTopLevelCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"unused\",\"type\":\"address\"}],\"name\":\"mapL1SenderContractAddressToL2Alias\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"myCallersAddressWithoutAliasing\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sendMerkleTreeState\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"partials\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"sendTxToL1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wasMyCallersAddressAliased\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"withdrawEth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]\n" + }, + { + "address": "0x0000000000000000000000000000000000000065", + "name": "ArbInfo", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Lookup for basic info about accounts and contracts.\n/// @notice Precompiled contract that exists in every Arbitrum chain at 0x0000000000000000000000000000000000000065.\ninterface ArbInfo {\n /// @notice Retrieves an account's balance\n function getBalance(address account) external view returns (uint256);\n\n /// @notice Retrieves a contract's deployed code\n function getCode(address account) external view returns (bytes memory);\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getCode\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n" + }, + { + "address": "0x0000000000000000000000000000000000000066", + "name": "ArbAddressTable", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/**\n * @title Allows registering / retrieving addresses at uint indices, saving calldata.\n * @notice Precompiled contract that exists in every Arbitrum chain at 0x0000000000000000000000000000000000000066.\n */\ninterface ArbAddressTable {\n /**\n * @notice Check whether an address exists in the address table\n * @param addr address to check for presence in table\n * @return true if address is in table\n */\n function addressExists(address addr) external view returns (bool);\n\n /**\n * @notice compress an address and return the result\n * @param addr address to compress\n * @return compressed address bytes\n */\n function compress(address addr) external returns (bytes memory);\n\n /**\n * @notice read a compressed address from a bytes buffer\n * @param buf bytes buffer containing an address\n * @param offset offset of target address\n * @return resulting address and updated offset into the buffer (revert if buffer is too short)\n */\n function decompress(bytes calldata buf, uint256 offset)\n external\n view\n returns (address, uint256);\n\n /**\n * @param addr address to lookup\n * @return index of an address in the address table (revert if address isn't in the table)\n */\n function lookup(address addr) external view returns (uint256);\n\n /**\n * @param index index to lookup address\n * @return address at a given index in address table (revert if index is beyond end of table)\n */\n function lookupIndex(uint256 index) external view returns (address);\n\n /**\n * @notice Register an address in the address table\n * @param addr address to register\n * @return index of the address (existing index, or newly created index if not already registered)\n */\n function register(address addr) external returns (uint256);\n\n /**\n * @return size of address table (= first unused index)\n */\n function size() external view returns (uint256);\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"addressExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"compress\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"buf\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"}],\"name\":\"decompress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"lookup\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"lookupIndex\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"size\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n" + }, + { + "address": "0x0000000000000000000000000000000000000067", + "name": "ArbBLS", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Disabled precompile, formerly used to register BLS public keys.\n/// @notice Precompiled contract that exists in every Arbitrum chain at 0x0000000000000000000000000000000000000067.\ninterface ArbBLS {\n\n}\n", + "abi": "[]\n" + }, + { + "address": "0x0000000000000000000000000000000000000068", + "name": "ArbFunctionTable", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Deprecated - Provided aggregator's the ability to manage function tables,\n// this enables one form of transaction compression.\n/// @notice The Nitro aggregator implementation does not use these,\n// so these methods have been stubbed and their effects disabled.\n/// They are kept for backwards compatibility.\n/// Precompiled contract that exists in every Arbitrum chain at 0x0000000000000000000000000000000000000068.\ninterface ArbFunctionTable {\n /// @notice Reverts since the table is empty\n function upload(bytes calldata buf) external;\n\n /// @notice Returns the empty table's size, which is 0\n function size(address addr) external view returns (uint256);\n\n /// @notice No-op\n function get(address addr, uint256 index)\n external\n view\n returns (\n uint256,\n bool,\n uint256\n );\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"size\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"buf\",\"type\":\"bytes\"}],\"name\":\"upload\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]\n" + }, + { + "address": "0x0000000000000000000000000000000000000069", + "name": "ArbosTest", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Deprecated - Provides a method of burning arbitrary amounts of gas,\n/// @notice This exists for historical reasons. Pre-Nitro, `ArbosTest` had additional methods only the zero address could call.\n/// These have been removed since users don't use them and calls to missing methods revert.\n/// Precompiled contract that exists in every Arbitrum chain at 0x0000000000000000000000000000000000000069.\ninterface ArbosTest {\n /// @notice Unproductively burns the amount of L2 ArbGas\n function burnArbGas(uint256 gasAmount) external pure;\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasAmount\",\"type\":\"uint256\"}],\"name\":\"burnArbGas\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]\n" + }, + { + "address": "0x000000000000000000000000000000000000006b", + "name": "ArbOwnerPublic", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Provides non-owners with info about the current chain owners.\n/// @notice Precompiled contract that exists in every Arbitrum chain at 0x000000000000000000000000000000000000006b.\ninterface ArbOwnerPublic {\n /// @notice See if the user is a chain owner\n function isChainOwner(address addr) external view returns (bool);\n\n /**\n * @notice Rectify the list of chain owners\n * If successful, emits ChainOwnerRectified event\n * Available in ArbOS version 11\n */\n function rectifyChainOwner(address ownerToRectify) external;\n\n /// @notice Retrieves the list of chain owners\n function getAllChainOwners() external view returns (address[] memory);\n\n /// @notice Gets the network fee collector\n function getNetworkFeeAccount() external view returns (address);\n\n /// @notice Get the infrastructure fee collector\n function getInfraFeeAccount() external view returns (address);\n\n /// @notice Get the Brotli compression level used for fast compression\n function getBrotliCompressionLevel() external view returns (uint64);\n\n /// @notice Get the next scheduled ArbOS version upgrade and its activation timestamp.\n /// Returns (0, 0) if no ArbOS upgrade is scheduled.\n /// Available in ArbOS version 20.\n function getScheduledUpgrade()\n external\n view\n returns (uint64 arbosVersion, uint64 scheduledForTimestamp);\n\n event ChainOwnerRectified(address rectifiedOwner);\n}\n", + "abi": "[{\"inputs\":[],\"name\":\"getAllChainOwners\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getInfraFeeAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNetworkFeeAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isChainOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n" + }, + { + "address": "0x000000000000000000000000000000000000006c", + "name": "ArbGasInfo", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Provides insight into the cost of using the chain.\n/// @notice These methods have been adjusted to account for Nitro's heavy use of calldata compression.\n/// Of note to end-users, we no longer make a distinction between non-zero and zero-valued calldata bytes.\n/// Precompiled contract that exists in every Arbitrum chain at 0x000000000000000000000000000000000000006c.\ninterface ArbGasInfo {\n /// @notice Get gas prices for a provided aggregator\n /// @return return gas prices in wei\n /// (\n /// per L2 tx,\n /// per L1 calldata byte\n /// per storage allocation,\n /// per ArbGas base,\n /// per ArbGas congestion,\n /// per ArbGas total\n /// )\n function getPricesInWeiWithAggregator(address aggregator)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n /// @notice Get gas prices. Uses the caller's preferred aggregator, or the default if the caller doesn't have a preferred one.\n /// @return return gas prices in wei\n /// (\n /// per L2 tx,\n /// per L1 calldata byte\n /// per storage allocation,\n /// per ArbGas base,\n /// per ArbGas congestion,\n /// per ArbGas total\n /// )\n function getPricesInWei()\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n /// @notice Get prices in ArbGas for the supplied aggregator\n /// @return (per L2 tx, per L1 calldata byte, per storage allocation)\n function getPricesInArbGasWithAggregator(address aggregator)\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /// @notice Get prices in ArbGas. Assumes the callers preferred validator, or the default if caller doesn't have a preferred one.\n /// @return (per L2 tx, per L1 calldata byte, per storage allocation)\n function getPricesInArbGas()\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /// @notice Get the gas accounting parameters. `gasPoolMax` is always zero, as the exponential pricing model has no such notion.\n /// @return (speedLimitPerSecond, gasPoolMax, maxTxGasLimit)\n function getGasAccountingParams()\n external\n view\n returns (\n uint256,\n uint256,\n uint256\n );\n\n /// @notice Get the minimum gas price needed for a tx to succeed\n function getMinimumGasPrice() external view returns (uint256);\n\n /// @notice Get ArbOS's estimate of the L1 basefee in wei\n function getL1BaseFeeEstimate() external view returns (uint256);\n\n /// @notice Get how slowly ArbOS updates its estimate of the L1 basefee\n function getL1BaseFeeEstimateInertia() external view returns (uint64);\n\n /// @notice Get the L1 pricer reward rate, in wei per unit\n /// Available in ArbOS version 11\n function getL1RewardRate() external view returns (uint64);\n\n /// @notice Get the L1 pricer reward recipient\n /// Available in ArbOS version 11\n function getL1RewardRecipient() external view returns (address);\n\n /// @notice Deprecated -- Same as getL1BaseFeeEstimate()\n function getL1GasPriceEstimate() external view returns (uint256);\n\n /// @notice Get L1 gas fees paid by the current transaction\n function getCurrentTxL1GasFees() external view returns (uint256);\n\n /// @notice Get the backlogged amount of gas burnt in excess of the speed limit\n function getGasBacklog() external view returns (uint64);\n\n /// @notice Get how slowly ArbOS updates the L2 basefee in response to backlogged gas\n function getPricingInertia() external view returns (uint64);\n\n /// @notice Get the forgivable amount of backlogged gas ArbOS will ignore when raising the basefee\n function getGasBacklogTolerance() external view returns (uint64);\n\n /// @notice Returns the surplus of funds for L1 batch posting payments (may be negative).\n function getL1PricingSurplus() external view returns (int256);\n\n /// @notice Returns the base charge (in L1 gas) attributed to each data batch in the calldata pricer\n function getPerBatchGasCharge() external view returns (int64);\n\n /// @notice Returns the cost amortization cap in basis points\n function getAmortizedCostCapBips() external view returns (uint64);\n\n /// @notice Returns the available funds from L1 fees\n function getL1FeesAvailable() external view returns (uint256);\n\n /// @notice Returns the equilibration units parameter for L1 price adjustment algorithm\n /// Available in ArbOS version 20\n function getL1PricingEquilibrationUnits() external view returns (uint256);\n\n /// @notice Returns the last time the L1 calldata pricer was updated.\n /// Available in ArbOS version 20\n function getLastL1PricingUpdateTime() external view returns (uint64);\n\n /// @notice Returns the amount of L1 calldata payments due for rewards (per the L1 reward rate)\n /// Available in ArbOS version 20\n function getL1PricingFundsDueForRewards() external view returns (uint256);\n\n /// @notice Returns the amount of L1 calldata posted since the last update.\n /// Available in ArbOS version 20\n function getL1PricingUnitsSinceUpdate() external view returns (uint64);\n\n /// @notice Returns the L1 pricing surplus as of the last update (may be negative).\n /// Available in ArbOS version 20\n function getLastL1PricingSurplus() external view returns (int256);\n}\n", + "abi": "[{\"inputs\":[],\"name\":\"getAmortizedCostCapBips\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentTxL1GasFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasAccountingParams\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasBacklog\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasBacklogTolerance\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1BaseFeeEstimate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1BaseFeeEstimateInertia\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1FeesAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1GasPriceEstimate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1PricingSurplus\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMinimumGasPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerBatchGasCharge\",\"outputs\":[{\"internalType\":\"int64\",\"name\":\"\",\"type\":\"int64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricesInArbGas\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"getPricesInArbGasWithAggregator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricesInWei\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"getPricesInWeiWithAggregator\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPricingInertia\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n" + }, + { + "address": "0x000000000000000000000000000000000000006d", + "name": "ArbAggregator", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Provides aggregators and their users methods for configuring how they participate in L1 aggregation.\n/// @notice Precompiled contract that exists in every Arbitrum chain at 0x000000000000000000000000000000000000006d\ninterface ArbAggregator {\n /// @notice Deprecated, customization of preferred aggregator is no longer supported\n /// @notice Get the address of an arbitrarily chosen batch poster.\n /// @param addr ignored\n /// @return (batchPosterAddress, true)\n function getPreferredAggregator(address addr) external view returns (address, bool);\n\n /// @notice Deprecated, there is no longer a single preferred aggregator, use getBatchPosters instead\n /// @notice Get default aggregator.\n function getDefaultAggregator() external view returns (address);\n\n /// @notice Get a list of all current batch posters\n /// @return Batch poster addresses\n function getBatchPosters() external view returns (address[] memory);\n\n /// @notice Adds newBatchPoster as a batch poster\n /// This reverts unless called by a chain owner\n /// @param newBatchPoster New batch poster\n function addBatchPoster(address newBatchPoster) external;\n\n /// @notice Get the address where fees to batchPoster are sent.\n /// @param batchPoster The batch poster to get the fee collector for\n /// @return The fee collectors address. This will sometimes but not always be the same as the batch poster's address.\n function getFeeCollector(address batchPoster) external view returns (address);\n\n /// @notice Set the address where fees to batchPoster are sent.\n /// This reverts unless called by the batch poster, its fee collector, or a chain owner\n /// @param batchPoster The batch poster to set the fee collector for\n /// @param newFeeCollector The new fee collector to set\n function setFeeCollector(address batchPoster, address newFeeCollector) external;\n\n /// @notice Deprecated, always returns zero\n /// @notice Get the tx base fee (in approximate L1 gas) for aggregator\n /// @param aggregator The aggregator to get the base fee for\n function getTxBaseFee(address aggregator) external view returns (uint256);\n\n /// @notice Deprecated, is now a no-op\n /// @notice Set the tx base fee (in approximate L1 gas) for aggregator\n /// Revert unless called by aggregator or the chain owner\n /// Revert if feeInL1Gas is outside the chain's allowed bounds\n /// @param aggregator The aggregator to set the fee for\n /// @param feeInL1Gas The base fee in L1 gas\n function setTxBaseFee(address aggregator, uint256 feeInL1Gas) external;\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newBatchPoster\",\"type\":\"address\"}],\"name\":\"addBatchPoster\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBatchPosters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDefaultAggregator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"batchPoster\",\"type\":\"address\"}],\"name\":\"getFeeCollector\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getPreferredAggregator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"}],\"name\":\"getTxBaseFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"batchPoster\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newFeeCollector\",\"type\":\"address\"}],\"name\":\"setFeeCollector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"aggregator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeInL1Gas\",\"type\":\"uint256\"}],\"name\":\"setTxBaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]\n" + }, + { + "address": "0x000000000000000000000000000000000000006e", + "name": "ArbRetryableTx", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/**\n * @title Methods for managing retryables.\n * @notice Precompiled contract in every Arbitrum chain for retryable transaction related data retrieval and interactions. Exists at 0x000000000000000000000000000000000000006e\n */\ninterface ArbRetryableTx {\n /**\n * @notice Schedule an attempt to redeem a redeemable tx, donating all of the call's gas to the redeem.\n * Revert if ticketId does not exist.\n * @param ticketId unique identifier of retryable message: keccak256(keccak256(ArbchainId, inbox-sequence-number), uint(0) )\n * @return txId that the redeem attempt will have\n */\n function redeem(bytes32 ticketId) external returns (bytes32);\n\n /**\n * @notice Return the minimum lifetime of redeemable txn.\n * @return lifetime in seconds\n */\n function getLifetime() external view returns (uint256);\n\n /**\n * @notice Return the timestamp when ticketId will age out, reverting if it does not exist\n * @param ticketId unique ticket identifier\n * @return timestamp for ticket's deadline\n */\n function getTimeout(bytes32 ticketId) external view returns (uint256);\n\n /**\n * @notice Adds one lifetime period to the life of ticketId.\n * Donate gas to pay for the lifetime extension.\n * If successful, emits LifetimeExtended event.\n * Revert if ticketId does not exist, or if the timeout of ticketId is already at least one lifetime period in the future.\n * @param ticketId unique ticket identifier\n * @return new timeout of ticketId\n */\n function keepalive(bytes32 ticketId) external returns (uint256);\n\n /**\n * @notice Return the beneficiary of ticketId.\n * Revert if ticketId doesn't exist.\n * @param ticketId unique ticket identifier\n * @return address of beneficiary for ticket\n */\n function getBeneficiary(bytes32 ticketId) external view returns (address);\n\n /**\n * @notice Cancel ticketId and refund its callvalue to its beneficiary.\n * Revert if ticketId doesn't exist, or if called by anyone other than ticketId's beneficiary.\n * @param ticketId unique ticket identifier\n */\n function cancel(bytes32 ticketId) external;\n\n /**\n * @notice Gets the redeemer of the current retryable redeem attempt.\n * Returns the zero address if the current transaction is not a retryable redeem attempt.\n * If this is an auto-redeem, returns the fee refund address of the retryable.\n */\n function getCurrentRedeemer() external view returns (address);\n\n /**\n * @notice Do not call. This method represents a retryable submission to aid explorers.\n * Calling it will always revert.\n */\n function submitRetryable(\n bytes32 requestId,\n uint256 l1BaseFee,\n uint256 deposit,\n uint256 callvalue,\n uint256 gasFeeCap,\n uint64 gasLimit,\n uint256 maxSubmissionFee,\n address feeRefundAddress,\n address beneficiary,\n address retryTo,\n bytes calldata retryData\n ) external;\n\n event TicketCreated(bytes32 indexed ticketId);\n event LifetimeExtended(bytes32 indexed ticketId, uint256 newTimeout);\n event RedeemScheduled(\n bytes32 indexed ticketId,\n bytes32 indexed retryTxHash,\n uint64 indexed sequenceNum,\n uint64 donatedGas,\n address gasDonor,\n uint256 maxRefund,\n uint256 submissionFeeRefund\n );\n event Canceled(bytes32 indexed ticketId);\n\n /// @dev DEPRECATED in favour of new RedeemScheduled event after the nitro upgrade\n event Redeemed(bytes32 indexed userTxHash);\n\n error NoTicketWithID();\n error NotCallable();\n}\n", + "abi": "[{\"inputs\":[],\"name\":\"NoTicketWithID\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotCallable\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"Canceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newTimeout\",\"type\":\"uint256\"}],\"name\":\"LifetimeExtended\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"retryTxHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sequenceNum\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"donatedGas\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"gasDonor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"maxRefund\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"submissionFeeRefund\",\"type\":\"uint256\"}],\"name\":\"RedeemScheduled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"userTxHash\",\"type\":\"bytes32\"}],\"name\":\"Redeemed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"TicketCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"getBeneficiary\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentRedeemer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLifetime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"getTimeout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"keepalive\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"ticketId\",\"type\":\"bytes32\"}],\"name\":\"redeem\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"l1BaseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callvalue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasFeeCap\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"gasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"maxSubmissionFee\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"feeRefundAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"retryTo\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"retryData\",\"type\":\"bytes\"}],\"name\":\"submitRetryable\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]\n" + }, + { + "address": "0x000000000000000000000000000000000000006f", + "name": "ArbStatistics", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Deprecated - Info about the rollup just prior to the Nitro upgrade\n/// @notice Precompiled contract in every Arbitrum chain for retryable transaction related data retrieval and interactions. Exists at 0x000000000000000000000000000000000000006f\ninterface ArbStatistics {\n /// @notice Get Arbitrum block number and other statistics as they were right before the Nitro upgrade.\n /// @return (\n /// Number of accounts,\n /// Total storage allocated (includes storage that was later deallocated),\n /// Total ArbGas used,\n /// Number of transaction receipt issued,\n /// Number of contracts created,\n /// )\n function getStats()\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n}\n", + "abi": "[{\"inputs\":[],\"name\":\"getStats\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n" + }, + { + "address": "0x0000000000000000000000000000000000000070", + "name": "ArbOwner", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/// @title Provides owners with tools for managing the rollup.\n/// @notice Calls by non-owners will always revert.\n/// Most of Arbitrum Classic's owner methods have been removed since they no longer make sense in Nitro:\n/// - What were once chain parameters are now parts of ArbOS's state, and those that remain are set at genesis.\n/// - ArbOS upgrades happen with the rest of the system rather than being independent\n/// - Exemptions to address aliasing are no longer offered. Exemptions were intended to support backward compatibility for contracts deployed before aliasing was introduced, but no exemptions were ever requested.\n/// Precompiled contract that exists in every Arbitrum chain at 0x0000000000000000000000000000000000000070.\ninterface ArbOwner {\n /// @notice Add account as a chain owner\n function addChainOwner(address newOwner) external;\n\n /// @notice Remove account from the list of chain owners\n function removeChainOwner(address ownerToRemove) external;\n\n /// @notice See if the user is a chain owner\n function isChainOwner(address addr) external view returns (bool);\n\n /// @notice Retrieves the list of chain owners\n function getAllChainOwners() external view returns (address[] memory);\n\n /// @notice Set how slowly ArbOS updates its estimate of the L1 basefee\n function setL1BaseFeeEstimateInertia(uint64 inertia) external;\n\n /// @notice Set the L2 basefee directly, bypassing the pool calculus\n function setL2BaseFee(uint256 priceInWei) external;\n\n /// @notice Set the minimum basefee needed for a transaction to succeed\n function setMinimumL2BaseFee(uint256 priceInWei) external;\n\n /// @notice Set the computational speed limit for the chain\n function setSpeedLimit(uint64 limit) external;\n\n /// @notice Set the maximum size a tx (and block) can be\n function setMaxTxGasLimit(uint64 limit) external;\n\n /// @notice Set the L2 gas pricing inertia\n function setL2GasPricingInertia(uint64 sec) external;\n\n /// @notice Set the L2 gas backlog tolerance\n function setL2GasBacklogTolerance(uint64 sec) external;\n\n /// @notice Get the network fee collector\n function getNetworkFeeAccount() external view returns (address);\n\n /// @notice Get the infrastructure fee collector\n function getInfraFeeAccount() external view returns (address);\n\n /// @notice Set the network fee collector\n function setNetworkFeeAccount(address newNetworkFeeAccount) external;\n\n /// @notice Set the infrastructure fee collector\n function setInfraFeeAccount(address newInfraFeeAccount) external;\n\n /// @notice Upgrades ArbOS to the requested version at the requested timestamp\n function scheduleArbOSUpgrade(uint64 newVersion, uint64 timestamp) external;\n\n /// @notice Sets equilibration units parameter for L1 price adjustment algorithm\n function setL1PricingEquilibrationUnits(uint256 equilibrationUnits) external;\n\n /// @notice Sets inertia parameter for L1 price adjustment algorithm\n function setL1PricingInertia(uint64 inertia) external;\n\n /// @notice Sets reward recipient address for L1 price adjustment algorithm\n function setL1PricingRewardRecipient(address recipient) external;\n\n /// @notice Sets reward amount for L1 price adjustment algorithm, in wei per unit\n function setL1PricingRewardRate(uint64 weiPerUnit) external;\n\n /// @notice Set how much ArbOS charges per L1 gas spent on transaction data.\n function setL1PricePerUnit(uint256 pricePerUnit) external;\n\n /// @notice Sets the base charge (in L1 gas) attributed to each data batch in the calldata pricer\n function setPerBatchGasCharge(int64 cost) external;\n\n /**\n * @notice Sets the Brotli compression level used for fast compression\n * Available in ArbOS version 12 with default level as 1\n */\n function setBrotliCompressionLevel(uint64 level) external;\n\n /// @notice Sets the cost amortization cap in basis points\n function setAmortizedCostCapBips(uint64 cap) external;\n\n /// @notice Releases surplus funds from L1PricerFundsPoolAddress for use\n function releaseL1PricerSurplusFunds(uint256 maxWeiToRelease) external returns (uint256);\n\n /// @notice Sets serialized chain config in ArbOS state\n function setChainConfig(string calldata chainConfig) external;\n\n // Emitted when a successful call is made to this precompile\n event OwnerActs(bytes4 indexed method, address indexed owner, bytes data);\n}\n", + "abi": "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes4\",\"name\":\"method\",\"type\":\"bytes4\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"OwnerActs\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"addChainOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllChainOwners\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getInfraFeeAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNetworkFeeAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"isChainOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxWeiToRelease\",\"type\":\"uint256\"}],\"name\":\"releaseL1PricerSurplusFunds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ownerToRemove\",\"type\":\"address\"}],\"name\":\"removeChainOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"newVersion\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"timestamp\",\"type\":\"uint64\"}],\"name\":\"scheduleArbOSUpgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"cap\",\"type\":\"uint64\"}],\"name\":\"setAmortizedCostCapBips\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newInfraFeeAccount\",\"type\":\"address\"}],\"name\":\"setInfraFeeAccount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"inertia\",\"type\":\"uint64\"}],\"name\":\"setL1BaseFeeEstimateInertia\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"pricePerUnit\",\"type\":\"uint256\"}],\"name\":\"setL1PricePerUnit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"equilibrationUnits\",\"type\":\"uint256\"}],\"name\":\"setL1PricingEquilibrationUnits\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"inertia\",\"type\":\"uint64\"}],\"name\":\"setL1PricingInertia\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"weiPerUnit\",\"type\":\"uint64\"}],\"name\":\"setL1PricingRewardRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"setL1PricingRewardRecipient\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"}],\"name\":\"setL2BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sec\",\"type\":\"uint64\"}],\"name\":\"setL2GasBacklogTolerance\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sec\",\"type\":\"uint64\"}],\"name\":\"setL2GasPricingInertia\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"limit\",\"type\":\"uint64\"}],\"name\":\"setMaxTxGasLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"priceInWei\",\"type\":\"uint256\"}],\"name\":\"setMinimumL2BaseFee\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newNetworkFeeAccount\",\"type\":\"address\"}],\"name\":\"setNetworkFeeAccount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int64\",\"name\":\"cost\",\"type\":\"int64\"}],\"name\":\"setPerBatchGasCharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"limit\",\"type\":\"uint64\"}],\"name\":\"setSpeedLimit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]\n" + }, + { + "address": "0x00000000000000000000000000000000000000c8", + "name": "NodeInterface", + "bytecode": "0xfe", + "compiler": "Not installed", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/** @title Interface for providing gas estimation for retryable auto-redeems and constructing outbox proofs\n * @notice This contract doesn't exist on-chain. Instead it is a virtual interface accessible at\n * 0x00000000000000000000000000000000000000C8\n * This is a cute trick to allow an Arbitrum node to provide data without us having to implement additional RPCs\n */\ninterface NodeInterface {\n /**\n * @notice Simulate the execution of a retryable ticket\n * @dev Use eth_estimateGas on this call to estimate gas usage of retryable ticket\n * Since gas usage is not yet known, you may need to add extra deposit (e.g. 1e18 wei) during estimation\n * @param sender unaliased sender of the L1 and L2 transaction\n * @param deposit amount to deposit to sender in L2\n * @param to destination L2 contract address\n * @param l2CallValue call value for retryable L2 message\n * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance\n * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled\n * @param data ABI encoded data of L2 message\n */\n function estimateRetryableTicket(\n address sender,\n uint256 deposit,\n address to,\n uint256 l2CallValue,\n address excessFeeRefundAddress,\n address callValueRefundAddress,\n bytes calldata data\n ) external;\n\n /**\n * @notice Constructs an outbox proof of an l2->l1 send's existence in the outbox accumulator.\n * @dev Use eth_call to call.\n * @param size the number of elements in the accumulator\n * @param leaf the position of the send in the accumulator\n * @return send the l2->l1 send's hash\n * @return root the root of the outbox accumulator\n * @return proof level-by-level branch hashes constituting a proof of the send's membership at the given size\n */\n function constructOutboxProof(uint64 size, uint64 leaf)\n external\n view\n returns (\n bytes32 send,\n bytes32 root,\n bytes32[] memory proof\n );\n\n /**\n * @notice Finds the L1 batch containing a requested L2 block, reverting if none does.\n * Use eth_call to call.\n * Throws if block doesn't exist, or if block number is 0. Use eth_call\n * @param blockNum The L2 block being queried\n * @return batch The sequencer batch number containing the requested L2 block\n */\n function findBatchContainingBlock(uint64 blockNum) external view returns (uint64 batch);\n\n /**\n * @notice Gets the number of L1 confirmations of the sequencer batch producing the requested L2 block\n * This gets the number of L1 confirmations for the input message producing the L2 block,\n * which happens well before the L1 rollup contract confirms the L2 block.\n * Throws if block doesnt exist in the L2 chain.\n * @dev Use eth_call to call.\n * @param blockHash The hash of the L2 block being queried\n * @return confirmations The number of L1 confirmations the sequencer batch has. Returns 0 if block not yet included in an L1 batch.\n */\n function getL1Confirmations(bytes32 blockHash) external view returns (uint64 confirmations);\n\n /**\n * @notice Same as native gas estimation, but with additional info on the l1 costs.\n * @dev Use eth_call to call.\n * @param data the tx's calldata. Everything else like \"From\" and \"Gas\" are copied over\n * @param to the tx's \"To\" (ignored when contractCreation is true)\n * @param contractCreation whether \"To\" is omitted\n * @return gasEstimate an estimate of the total amount of gas needed for this tx\n * @return gasEstimateForL1 an estimate of the amount of gas needed for the l1 component of this tx\n * @return baseFee the l2 base fee\n * @return l1BaseFeeEstimate ArbOS's l1 estimate of the l1 base fee\n */\n function gasEstimateComponents(\n address to,\n bool contractCreation,\n bytes calldata data\n )\n external\n payable\n returns (\n uint64 gasEstimate,\n uint64 gasEstimateForL1,\n uint256 baseFee,\n uint256 l1BaseFeeEstimate\n );\n\n /**\n * @notice Estimates a transaction's l1 costs.\n * @dev Use eth_call to call.\n * This method is similar to gasEstimateComponents, but doesn't include the l2 component\n * so that the l1 component can be known even when the tx may fail.\n * This method also doesn't pad the estimate as gas estimation normally does.\n * If using this value to submit a transaction, we'd recommend first padding it by 10%.\n * @param data the tx's calldata. Everything else like \"From\" and \"Gas\" are copied over\n * @param to the tx's \"To\" (ignored when contractCreation is true)\n * @param contractCreation whether \"To\" is omitted\n * @return gasEstimateForL1 an estimate of the amount of gas needed for the l1 component of this tx\n * @return baseFee the l2 base fee\n * @return l1BaseFeeEstimate ArbOS's l1 estimate of the l1 base fee\n */\n function gasEstimateL1Component(\n address to,\n bool contractCreation,\n bytes calldata data\n )\n external\n payable\n returns (\n uint64 gasEstimateForL1,\n uint256 baseFee,\n uint256 l1BaseFeeEstimate\n );\n\n /**\n * @notice Returns the proof necessary to redeem a message\n * @param batchNum index of outbox entry (i.e., outgoing messages Merkle root) in array of outbox entries\n * @param index index of outgoing message in outbox entry\n * @return proof Merkle proof of message inclusion in outbox entry\n * @return path Merkle path to message\n * @return l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)\n * @return l1Dest destination address for L1 contract call\n * @return l2Block l2 block number at which sendTxToL1 call was made\n * @return l1Block l1 block number at which sendTxToL1 call was made\n * @return timestamp l2 Timestamp at which sendTxToL1 call was made\n * @return amount value in L1 message in wei\n * @return calldataForL1 abi-encoded L1 message data\n */\n function legacyLookupMessageBatchProof(uint256 batchNum, uint64 index)\n external\n view\n returns (\n bytes32[] memory proof,\n uint256 path,\n address l2Sender,\n address l1Dest,\n uint256 l2Block,\n uint256 l1Block,\n uint256 timestamp,\n uint256 amount,\n bytes memory calldataForL1\n );\n\n // @notice Returns the first block produced using the Nitro codebase\n // @dev returns 0 for chains like Nova that don't contain classic blocks\n // @return number the block number\n function nitroGenesisBlock() external pure returns (uint256 number);\n\n // @notice Returns the L1 block number of the L2 block\n // @return l1BlockNum The L1 block number\n function blockL1Num(uint64 l2BlockNum) external view returns (uint64 l1BlockNum);\n\n /**\n * @notice Finds the L2 block number range that has the given L1 block number\n * @param blockNum The L1 block number to search for the range\n * Throws if no L2 block exist with the given L1 block number\n * @return firstBlock The first L2 block number with the given L1 block number\n * @return lastBlock The last L2 block number with the given L1 block number\n */\n function l2BlockRangeForL1(uint64 blockNum)\n external\n view\n returns (uint64 firstBlock, uint64 lastBlock);\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"size\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"leaf\",\"type\":\"uint64\"}],\"name\":\"constructOutboxProof\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"send\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"deposit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"l2CallValue\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"excessFeeRefundAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"callValueRefundAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"estimateRetryableTicket\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"}],\"name\":\"findBatchContainingBlock\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batch\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"contractCreation\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"gasEstimateComponents\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"gasEstimate\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"gasEstimateForL1\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"baseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1BaseFeeEstimate\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"contractCreation\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"gasEstimateL1Component\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"gasEstimateForL1\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"baseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1BaseFeeEstimate\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"name\":\"getL1Confirmations\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"confirmations\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchNum\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"}],\"name\":\"legacyLookupMessageBatchProof\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"path\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"l2Sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Dest\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"l2Block\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1Block\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"calldataForL1\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nitroGenesisBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]\n" + }, + { + "address": "0x00000000000000000000000000000000000000c9", + "name": "NodeInterfaceDebug", + "bytecode": "0xfe", + "compiler": "Not installed", + "source": "// Copyright 2021-2022, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/** @title An extension to NodeInterface not meant for public consumption. Do not call.\n * @notice This contract doesn't exist on-chain. Instead it is a virtual interface accessible at 0xc9.\n * These methods add additional debugging and network monitoring instruments not intended for end users and\n * as such may change without notice.\n */\n\ninterface NodeInterfaceDebug {\n struct RetryableInfo {\n uint64 timeout;\n address from;\n address to;\n uint256 value;\n address beneficiary;\n uint64 tries;\n bytes data;\n }\n\n /**\n * @notice gets a retryable\n * @param ticket the retryable's id\n * @return retryable the serialized retryable\n */\n function getRetryable(bytes32 ticket) external view returns (RetryableInfo memory retryable);\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"ticket\",\"type\":\"bytes32\"}],\"name\":\"getRetryable\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"timeout\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"beneficiary\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"tries\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"struct NodeInterfaceDebug.RetryableInfo\",\"name\":\"retryable\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]\n" + }, + { + "address": "0x00000000000000000000000000000000000000ff", + "name": "ArbDebug", + "bytecode": "0xfe", + "compiler": "L2 Precompile (go 1.17)", + "source": "// Copyright 2021-2023, Offchain Labs, Inc.\n// For license information, see https://github.com/OffchainLabs/nitro-contracts/blob/main/LICENSE\n// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.4.21 <0.9.0;\n\n/**\n * @title A test contract whose methods are only accessible in debug mode\n * @notice Precompiled contract that exists in every Arbitrum chain at 0x00000000000000000000000000000000000000ff.\n */\ninterface ArbDebug {\n /// @notice Caller becomes a chain owner\n function becomeChainOwner() external;\n\n /// @notice Emit events with values based on the args provided\n function events(bool flag, bytes32 value) external payable returns (address, uint256);\n\n /// @notice Tries (and fails) to emit logs in a view context\n function eventsView() external view;\n\n // Events that exist for testing log creation and pricing\n event Basic(bool flag, bytes32 indexed value);\n event Mixed(\n bool indexed flag,\n bool not,\n bytes32 indexed value,\n address conn,\n address indexed caller\n );\n event Store(\n bool indexed flag,\n address indexed field,\n uint24 number,\n bytes32 value,\n bytes store\n );\n\n function customRevert(uint64 number) external pure;\n\n function legacyError() external pure;\n\n error Custom(uint64, string, bool);\n error Unused();\n}\n", + "abi": "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"name\":\"Custom\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unused\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"}],\"name\":\"Basic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"not\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"conn\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Mixed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"field\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint24\",\"name\":\"number\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"store\",\"type\":\"bytes\"}],\"name\":\"Store\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"becomeChainOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"number\",\"type\":\"uint64\"}],\"name\":\"customRevert\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"flag\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"value\",\"type\":\"bytes32\"}],\"name\":\"events\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"legacyError\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]\n" + } +] \ No newline at end of file diff --git a/config/runtime.exs b/config/runtime.exs index 8945fd26cd..7deb0e20a0 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -246,10 +246,23 @@ config :explorer, Explorer.Chain.Events.Listener, else: true ) +precompiled_config_base_dir = + case config_env() do + :prod -> "/app/" + _ -> "./" + end + +precompiled_config_default_path = + case ConfigHelper.chain_type() do + "arbitrum" -> "#{precompiled_config_base_dir}config/assets/precompiles-arbitrum.json" + _ -> nil + end + config :explorer, Explorer.ChainSpec.GenesisData, chain_spec_path: System.get_env("CHAIN_SPEC_PATH"), emission_format: System.get_env("EMISSION_FORMAT", "DEFAULT"), - rewards_contract_address: System.get_env("REWARDS_CONTRACT", "0xeca443e8e1ab29971a45a9c57a6a9875701698a5") + rewards_contract_address: System.get_env("REWARDS_CONTRACT", "0xeca443e8e1ab29971a45a9c57a6a9875701698a5"), + precompiled_config_path: System.get_env("PRECOMPILED_CONTRACTS_CONFIG_PATH", precompiled_config_default_path) address_sum_global_ttl = ConfigHelper.parse_time_env_var("CACHE_ADDRESS_SUM_PERIOD", "1h") diff --git a/docker/Dockerfile b/docker/Dockerfile index 1990e9ee0e..779985c1ab 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -85,3 +85,4 @@ COPY --from=builder /opt/release/blockscout . COPY --from=builder /app/apps/explorer/node_modules ./node_modules COPY --from=builder /app/config/config_helper.exs ./config/config_helper.exs COPY --from=builder /app/config/config_helper.exs /app/releases/${RELEASE_VERSION}/config_helper.exs +COPY --from=builder /app/config/assets/precompiles-arbitrum.json ./config/assets/precompiles-arbitrum.json