Introduction
Welcome to The Otterscan Book.
This is the official documentation for Otterscan, an open-source, fast, local, laptop-friendly Ethereum block explorer.
This book is open-source and available on GitHub: https://github.com/otterscan/otterscan-book.
It is also available online at: https://docs.otterscan.io/
This chapter starts with an overview of what is Otterscan.
Then we move into a high level explanation of its architecture.
Which chains are compatible with Otterscan?
How contract verification is handled.
What is it?
Otterscan is a block explorer for EVM chains designed to run locally with an archive node companion - more specifically, Erigon.
This approach brings many advantages, as follows.
Privacy
You are querying your own node, so you are not sending your IP address or queries to an external, third-party node.
Fast
Since you are querying your local archive node, everything is fast. No network roundtrips are necessary.
Actually, very fast
This software was designed to be a companion of Erigon, a blazingly fast archive node.
Really, it is even faster
The standard web3 JSON-RPC methods are quite verbose and generic requiring many calls to gather many pieces of information at client side.
We've implemented some custom methods at the rpcdaemon
level, so less information is needed to be JSON-marshalled and transmitted over network.
Architecture
Otterscan itself can be split into three parts:
Otterscan UI
This is the main block explorer UI that end users will interact with.
It is a React single-page application, and the repository is available at https://github.com/otterscan/otterscan.
Otterscan API Specification
This is the set of API definitions the Otterscan UI depends on.
See more here.
Otterscan API Implementation
This is server software that implements the Otterscan API.
The reference implementation is Erigon, but any Ethereum client (in theory) could implement it.
Supported Networks
Otterscan runs on any network that has a client implementing the Otterscan API. Below is a non-exhaustive list.
Erigon
- Ethereum
- Mainnet
- Sepolia and Holesky testnets
- Gnosis Chain
- Gnosis mainnet
- Chiado testnet
- Polygon
- Polygon PoS
- Amoy testnet
- Ephemery testnet
OP-Erigon
- Any network from the Superchain Registry (Optimism, Base, Zora, etc).
Anvil
- Local devnets
Anvil implements the Otterscan API, so you can point your Otterscan installation to an Anvil RPC endpoint and have an explorer for your local devnet.
Contract Verification
We display verified contracts using information from Sourcify.
For more details on how the integration works, please check the Contract verification chapter.
Installation
First of all, take a look at how we envision all Otterscan components should connect to each other. Understanding this architecture will make it easier to solve common network issues.
Make sure you have a working and synced Erigon instance. Setting up Erigon is out of scope of this book.
Otterscan RPC support is already embedded in every Erigon node >= v2.29.0
. You just need to enable it.
This software is currently distributed as a docker image.
Otterscan is a merged explorer, which means it can optionally display beacon chain data for chains that support it.
Otterscan v2.x has some EXPERIMENTAL extra indexers.
Once you finish installing it, you can check if everything is working as expected.
Architecture overview
You can run all components that make Otterscan possible in your own machine, but it is likely you are going to run it in your local network.
For a better understanding, let's assume every component is in a different machine. First of all, you need to make sure all endpoints are accessible from the browser you are going to use.
The following sections will explain in more details the required configuration for each of these components.
Running Otterscan with Erigon
Enable the Otterscan RPC namespace in Erigon
When running Erigon, make sure to enable the eth
, erigon
, trace
and ots
namespaces in addition to whatever CLI options you are using to start Erigon. The trace
namespace is used for transaction state diffs.
Enabling namespaces in Erigon is done through the --http.api
argument.
Example
erigon --http.api "eth,erigon,trace,ots[,<other-namespaces>]" [<other CLI arguments...>]
ots
stands for Otterscan, and it is the JSON-RPC namespace we use for our own custom APIs.
Enable CORS
CORS is required for the browser to call the Erigon node directly.
This is done using the --http.corsdomain
argument. Make sure it is set correctly to the domain you are binding your Erigon node to.
💡 If you are going to enable CORS for all domains, make sure to quote it, i.e.
--http.corsdomain='*'
otherwise the wildcard (*
) may be captured by the shell.
Example
erigon --http.corsdomain '*' [<other CLI arguments...>]
Optional flags
--ots.search.max.pagesize <N>
By default the ots_searchTransactions*
JSON-RPC methods are capped at server level to max page size of 25, no matter what page size is specified in the method parameters.
That is intentional, in order to prevent DoS'ing the node if users were able to specify unbounded page sizes.
In you are using the Otterscan API directly, you may want to increase the maximum allowed page size by setting this parameter on Erigon startup.
Install and running Otterscan
Run Otterscan Docker image from Docker Hub
The official Otterscan repo on Docker Hub is here.
There is an image tag for each release tag on GitHub, e.g., v2.5.0
, v2.6.0
. In addition to that, there is a develop
tag which is built automatically from the develop
branch on GitHub in case you want to run the most recent develop build.
Example
docker run --rm -p 5100:80 --name otterscan -d otterscan/otterscan:<versiontag>
This will download the Otterscan image from Docker Hub, run it locally under the otterscan
container name using the default parameters, and bind it to port 5100 (see the -p
docker run parameter).
To stop the Otterscan service, run:
docker stop otterscan
By default, it assumes your Erigon node is at http://127.0.0.1:8545
, and users' browsers will try to connect to this RPC URL. You can override the URL by setting the ERIGON_URL
env variable in the container:
docker run --rm -p 5100:80 --name otterscan -d --env ERIGON_URL="<your-erigon-node-url>" otterscan/otterscan:<versiontag>
You can override the entire Otterscan configuration with the OTTERSCAN_CONFIG
env variable:
docker run \
--rm \
-p 5100:80 \
--name otterscan \
-d \
--env OTTERSCAN_CONFIG='{
"erigonURL": "http://127.0.0.1:8545",
"assetsURLPrefix": "http://127.0.0.1:5175",
"branding": {
"siteName": "My Otterscan",
"networkTitle": "Dev Network"
},
}' \
otterscan/otterscan:latest
These settings overwrite the Otterscan config file on container startup. To disable this behavior, pass --env DISABLE_CONFIG_OVERWRITE=1
to the Docker command.
This is the preferred way to run Otterscan. You can read about other ways here.
Run Otterscan development image from Docker Hub
The develop
branch is automatically built and published on Docker Hub.
There is a helper script that always pulls the latest build and sets the required parameters.
From the repository root:
./scripts/run-ots-develop.sh <ERIGON-RPC-URL> <CL-REST-API-URL>
It'll start a container under the name otterscan
.
Beacon chain support
Since The Merge, running a consensus layer node (CL) is required alongside the execution layer node (EL).
For merged chains, Otterscan can optionally display CL information. Most known merged chains are Ethereum and Gnosis (mainnet and testnets).
First you'll need to make sure your CL node is fully synced and then enable its REST API support.
You can then enable it in Otterscan.
Overview
Like the EL, which has blocks and transactions, CL has its own set of data structures. It is possible to read this information from CL through a standardized Beacon Chain REST API.
Gotchas
There are many CL implementations that you can combine with your EL, hence many possible issues or different behaviors, even in the same implementation depending on how it is configured.
We have been mainly using/testing both Lighthouse (in its "experimental tree states") and Erigon's own internal CL "Caplin" since they have checkpoint sync and backfilling.
It is out-of-scope of this document to review all existing CL implementations.
Let's now describe in more detail some issues we noticed.
Checkpoint vs. genesis sync
Checkpoint sync is a nice feature that allows you to "jump" directly to a finalized slot and have a functional CL node in a matter of minutes.
However, by doing that you won't have the details of historical slots, epochs, etc.
That may not be a problem if you are only concerned with your current validator balance, for example. Just be aware of that.
The alternative, if you want to browse all beacon chain history, is to do a genesis sync, but that is very slow on mainnet.
Backfilling
Some CL implementations (e.g. Lighthouse) have a nice feature called backfilling, where you can do a checkpoint sync and have a functional CL node in minutes, while historical information is downloaded in background.
That may be a better alternative to genesis sync if you want to have all historical info.
Some historical operations can be slow on default settings
Let's take as an example the /eth/v1/validator/duties/proposer/
call that we use to obtain the elected block proposers for a given epoch.
Its main use is to answer the question: for a missed slot, who was the elected validator who missed it?
Well, in Lighthouse, using the default settings, querying an old epoch is very slow: https://github.com/sigp/lighthouse/issues/3770
The alternative is to change data granularity, trading off disk space for speed.
There may be other cases with different trade-offs. Be aware of how your CL implementation works.
Enabling the CL REST API
Instructions for enabling the REST API are dependent on which CL implementation you are using.
It is out-of-scope of this document to explain how it is done since there are many CL implementations. Please check their docs.
We'll provide instructions for Lighthouse and Caplin as an example, since they are the implementations we use in our tests.
But the key points you need to observe are:
- Default port number: that is not standardized, Lighthouse uses
5052
, Prysm uses3500
, etc. - Bind the REST web server to the correct network interface: it is usually set to
localhost
for security reasons, be sure to explicitly bind it to your network interface in order for your browser to reach it. You'll most likely want to bind it to0.0.0.0
. - Enable CORS.
Example instructions:
Lighthouse
As of Lighthouse 3.3.0
, the required parameters to make it work with Otterscan are:
lighthouse beacon \
--http \
--http-address "0.0.0.0" \
[--http-port <REST-API-port-number> \]
--http-allow-origin '*' \
--genesis-backfill \
[--disable-backfill-rate-limiting \]
[<other CLI arguments>]
--http-port
is optional, by default it binds to:5052
.--genesis-backfill
is required in order to backfill slot data back to the genesis. If you don't specify that parameter and use checkpoint sync, only slot info after the checkpoint will be available.--disable-backfill-rate-limiting
is optional, but if your node is used exclusively for Otterscan you'll probably want to enable it in order to speed up backfilling during the first sync.
Caplin
💡 Caplin is being actively developed, and this document may contain outdated instructions. Please check the Erigon docs if you think that's the case.
Make sure to activate all of the following erigon
arguments:
--internalcl
: activate internal CL support (Erigon 2)💡 This flag is not necessary on Erigon 3 since internal CL is enabled by default
--caplin.archive
: activate Caplin archive node support--caplin.backfilling
,--caplin.backfilling.blob
,--caplin.backfilling.blob.no-pruning
: enable backfilling of historical CL blocks--beacon.api "beacon,builder,config,debug,events,node,validator,lighthouse"
: enable beacon chain REST API namespaces--beacon.api.addr "0.0.0.0"
: expose the REST API endpoint as necessary (default islocalhost
)--beacon.api.port <port-number>
: change the port number for the REST API endpoint (optional; default is5555
)--beacon.api.cors.allow-methods "GET,OPTIONS"
,--beacon.api.cors.allow-origins '*'
: enable CORS for the REST API endpoint
Enabling in Otterscan
Add the BEACON_API_URL
environment parameter to your docker run
command. The URL must point to an exposed CL REST endpoint which is reachable from your browser.
Example:
docker run \
--rm \
--name otterscan \
-d \
-p 5100:80 \
--env ERIGON_URL="http://my-erigon-node:8545" \
--env BEACON_API_URL="http://my-lighthouse-node:5052" \
otterscan/otterscan:<tag>
Otterscan 2.x EXPERIMENTAL indexers
Otterscan v2.x supports some experimental, optional indexers.
They require some extra steps to be enabled.
⚠️ The following instructions are for Erigon 2.x but their support are deprecated. We are currently working on Erigon 3 support and both new APIs and features in the UI will likely change.
⚠️ They require MORE disk space and first sync time in order to generate the extra information.
Clone and build Erigon + OTS2 support
Checkout the ots2-alpha4
branch from Erigon repository: https://github.com/erigontech/erigon/tree/ots2-alpha4
Build it as usual with make
command.
Enable OTS2 indexers inside Erigon
Change Erigon CLI args to:
- Enable
ots2
API namespace in addition toots
. - Add
--experimental.ots2
CLI arg.
For example, if your Erigon start command is:
erigon \
--http.api "eth,erigon,trace,ots" \
[<other CLI arguments>]
change it to:
erigon \
--http.api "eth,erigon,trace,ots,ots2" \
--experimental.ots2 \
[<other CLI arguments>]
Enable OTS2 mode in Otterscan
Add the OTS2=true
env variable when starting the docker container.
For example, if your docker start command is:
docker run \
--rm \
--name otterscan \
-d \
-p 5100:80 \
--env ERIGON_URL="<erigon-url>" \
otterscan/otterscan:v2.3.0
change it to:
docker run \
--rm \
--name otterscan \
-d \
-p 5100:80 \
--env ERIGON_URL="<erigon-url>" \
--env OTS2=true \
otterscan/otterscan:v2.3.0
Other ways to run Otterscan
(Alternative 1) Build Otterscan docker image locally and run it
If you don't want to download it from Docker Hub, you can build the docker image from the sources and run it.
If you just want to build the image locally, there is no need to install the development toolchain, just make sure you have a recent working Docker installation.
This method requires only git
and docker
.
The entire build process will take place inside the docker multi-stage build.
Clone Otterscan repo.
git clone https://github.com/otterscan/otterscan.git
cd otterscan
npm run docker-build
This will run the entire build process inside a build container, merge the production build of the React app with pre-made assets from otterscan-assets
project into the same image format it is published in Docker Hub, but locally under the name otterscan
.
Then you can start/stop it using the commands:
npm run docker-start
<browse locally on http://localhost:5273>
npm run docker-stop
(Alternative 2) Run a development build from the source
First, a brief explanation about the app:
- The app itself is a simple React app which will be run locally and communicates with your Erigon node.
- The app makes use of external data sources, like icons, signatures, etc. They require you to run a separate process to serve them. They are made available as a nginx Docker image.
These instructions are subjected to changes in future for the sake of simplification.
Make sure you have a working node 20/npm 10 installation.
By default, it assumes your erigon
process is serving requests at http://localhost:8545, a beacon chain REST API serves requests at http://localhost:5052, and assets are hosted at http://localhost:5175.
You can customize these URLs by creating a .env.development.local
file at the root of the repository (automatically git ignored) and adding the following entries:
VITE_ERIGON_URL=<your-erigon-JSON-RPC-endpoint>
VITE_BEACON_API_URL=<your-beacon-chain-REST-API-endpoint>
VITE_ASSETS_URL=<your-assets-endpoint>
Start serving the assets server by running the following Docker image:
npm run assets-start
To stop it, run:
npm run assets-stop
By default they run at http://localhost:5175
To run Otterscan development build:
npm ci
npm start
Otterscan should now be running at http://localhost:5173
Assets Server
Otterscan can make use of several external data sources to give context to on-chain data. The external data sources are served to Otterscan clients at the location given by the assetsURLPrefix
config option.
Typically, these assets are served using the otterscan/otterscan-assets
Docker image from the otterscan-assets repository. In a development environment, you can use npm run assets-start
and npm run assets-stop
to run the Docker commands.
Setups requiring custom or private data can serve assets manually following the same structure.
Structure Overview
The asset server serves files in the following folder structure:
- assets: Contains token logos from https://github.com/trustwallet/assets.
[chain_id]
: Each subdirectory corresponds to a specific blockchain network, such as Ethereum (1
).
- chains: Chain data from https://github.com/ethereum-lists/chains.
eip155-[chain_id].json
- signatures: A directory mapping function selectors to function signatures, in the format from https://github.com/ethereum-lists/4bytes.
- Each filename is a 4-byte selector (e.g.,
a9059cbb
), and the file contents are the corresponding function signature (e.g.,transfer(address,uint256)
).
- Each filename is a 4-byte selector (e.g.,
- topic0: A directory mapping log topic hashes to event signatures, in the format from https://github.com/otterscan/topic0.
- Each filename is a 32-byte hash (e.g.,
ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
), and the file contents are the corresponding event signature (e.g.,Transfer(address indexed from,address indexed to,uint256 value)
).
- Each filename is a 32-byte hash (e.g.,
Manually recreating the assets folder structure
You can recreate the assets folder structure and serve it manually.
First, create a new directory and clone all the data repositories into it:
mkdir external-repos
cd external-repos
git clone https://github.com/trustwallet/assets.git trustwallet-assets
git clone https://github.com/ethereum-lists/chains.git chains
git clone https://github.com/ethereum-lists/4bytes.git 4bytes
git clone https://github.com/otterscan/topic0.git topic0
cd ..
Create the main assets-server
directory:
mkdir assets-contents
cd assets-contents
Set up symbolic links pointing to external data from previously cloned repositories:
ln -s ../external-repos/chains/_data/chains chains
ln -s ../external-repos/4bytes/signatures signatures
ln -s ../external-repos/topic0/with_parameter_names topic0
Set up a symbolic link pointing to the token logos (replace ethereum
with the chain name):
mkdir assets
ln -s ../external-repos/trustwallet-assets/blockchains/ethereum/assets ./assets/1
(Optional.) Populate a contracts
folder with the Sourcify repository structure and reuse the assets server as a custom Sourcify source.
Spin up HTTP server
In a production environment, use a real HTTP server application, like how the otterscan-assets
image uses nginx
.
In a development environment, you can use the built-in, single-threaded http.server
Python module to serve the current directory:
python3 -m http.server 5175
The assets server will be hosted at http://localhost:5175.
Validating the installation
You can make sure everything is working correctly if the homepage is able to show the latest block/timestamp your Erigon node is at just below the search button.
If the beacon chain support is properly configured, you should see the latest finalized slot as well.
Configuration options
In this chapter we first explain how the application configuration is read.
Then we explore all the available configuration options.
Specifying the configuration
There are multiple ways to configure Otterscan base settings, depending on how you want to run it.
Static hardcoded node/chain ID
Define a VITE_CONFIG_JSON
environment variable containing a JSON string with the entire config.
Fetch config from server
If you don't specify a VITE_CONFIG_JSON
variable, the dapp will fetch a <your-domain>/config.json
file on page load.
That file can be overwritten server-side and changes will be reflected when users refresh the page.
You are free to define the best way to do that depending on how you package your Otterscan distribution.
For reference, our official Docker image accepts initialization parameters that overwrite that file when the container is initialized.
Development
During development, define a VITE_CONFIG_JSON
variable inside a .env.development.local
file, and vite will use those settings automatically.
Otterscan uses dotenv, and that file is automatically .gitignore
'd and not pushed into version control.
Example .env.development.local
file:
VITE_CONFIG_JSON='
{
"erigonURL": "http://your-erigon-node-ip:8545",
"beaconAPI": "http://your-beacon-node-ip:5052",
"assetsURLPrefix": "http://localhost:5175",
"experimentalFixedChainId": 11155111,
"chainInfo": {
"name": "Sepolia Testnet",
"faucets": [],
"nativeCurrency": {
"name": "Sepolia Ether",
"symbol": "SEPETH",
"decimals": 18
}
},
"sourcifySources": {
"ipfs": "https://ipfs.io/ipns/repo.sourcify.dev",
"central_server": "https://repo.sourcify.dev"
}
}
'
Production
In a production environment, the VITE_CONFIG_JSON
environment variable needs to be defined at build time, otherwise it has no effect; in that case, the node/chain config will be static.
That way the config won't need to be fetched from server—one less network call on page load. That's the recommended setting for controlled hosted environments where you control the node your users will connect to.
You can either:
- Make your CI
export
aVITE_CONFIG_JSON
env variable with the desired settings. - During build time, make sure there is a
.env.production
file with aVITE_CONFIG_JSON
variable defined in it.
Options
Otterscan can be customized in many different ways.
If your chain is an Optimism L2 Superchain, you can wire that Otterscan instance with an L1 one.
Price resolvers can be customized as well.
If you are running Otterscan against a non-standard chain, but you are sure Erigon can run it, you can explicitly specify the configuration.
In case you are running your own Sourcify instance, that's configurable as well.
Branding
Integrators can customize some aspects of the Otterscan UI in order to match their brand.
Customization
Some components in the user interface can be customized in the config under the branding
key:
{
"branding": {
"siteName": "Otterscan",
"networkTitle": "Holesky Testnet",
"hideAnnouncements": false
}
}
siteName
: Sets the name displayed on the home page, header, and page titles.networkTitle
: If set, adds an additional name to page titles.hideAnnouncements
: If set to true, hides new feature announcements from the home page.
Logo
To replace the default Otterscan logo with your own, simply replace src/otter.png
with a different PNG image. Rebuild Otterscan for the change to take effect.
Optimism
For chains which follow the OP Stack, configure the opChainSettings
key in the config:
l1ExplorerURL
: The root URL of a block explorer for the layer-1 of this chain, without a trailing forward slash. This appears on block pages in the "L1 Epoch" row.
Example for Sepolia:
{
"opChainSettings": {
"l1ExplorerURL": "https://sepolia.otterscan.io"
}
}
Price oracles
Otterscan makes use of on-chain Chainlink data feeds for fetching historical price data from Chainlink smart contracts compatible with the AggregatorV3 interface which act as price oracles. The native token price is fetched from a Chainlink data feed smart contract.
The Ethereum mainnet has a registry which Otterscan uses to look up token prices for supported tokens. On other chains, and for tokens not in the registry, Otterscan can estimate a token's price using information from on-chain decentralized exchanges.
NOTE: The prices estimated from on-chain decentralized exchanges can be manipulated, especially when tokens have low liquidity or are unable to be traded normally. This price estimation feature returns "best guess" prices; Otterscan certainly cannot guarantee that all tokens with an estimated price have a liquid market or that the prices shown are accurate.
To configure Otterscan's price oracle usage, configure the priceOracleInfo
key in the config:
nativeTokenPrice
: If configured, shows the native token price at the top of the page.ethUSDOracleAddress
: AggregatorV3-compatible smart contract that returns the price of the native token in USD. If Chainlink does not support your chain, you may consider deploying a smart contract which implements the AggregatorV3 interface yet derives price data from on-chain sources.ethUSDOracleDecimals
: Number of decimals used by the oracle smart contract.
wrappedEthAddress
: The address of the wrapped native token contract, which should match the WETH variable in Uniswap router contracts. This is used to estimate the price of tokens which have at least one Uniswap pool paired with the wrapped native token.uniswapV2
: If configured, uses UniswapV2 pairs as sources of price information.factoryAddress
: The UniswapV2 factory address.
uniswapV3
: If configured, uses UniswapV3 pools as sources of price information. Pools at the 0.01%, 0.05%, 0.3%, and 1% price tiers are queried.factoryAddress
: The UniswapV3 factory address.
Example for Ethereum mainnet:
{
"priceOracleInfo": {
"nativeTokenPrice": {
"ethUSDOracleAddress": "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",
"ethUSDOracleDecimals": 8
},
"wrappedEthAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"uniswapV2": {
"factoryAddress": "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"
},
"uniswapV3": {
"factoryAddress": "0x1F98431c8aD98523631AE4a59f267346ea31F984"
}
}
}
Recognizing nonstandard chains
By default, Otterscan recognizes several chains, including the Ethereum mainnet and several Ethereum test networks. For other chains, specify either (1) a chainInfo
key in the Otterscan config, or (2) create a JSON file accessible at {assetsURLPrefix}/chains/eip155-{chainId}.json
. In both cases, use the ethereum-lists structure to describe the properties of the chain:
name
: The full name of the network, such as "Ethereum Mainnet".faucets
: A list of faucet URLs which are accessible at the/faucets
endpoint and navigable from address pages. The special string${ADDRESS}
can be included in the URL and will be replaced with the address the user navigated from.nativeCurrency
: Describes the native currency of the chain; this is analogous to ETH on the Ethereum mainnet.name
: Full name of the native currency, e.g. "Ether".symbol
: Few-character symbol used in trading, e.g. "ETH".decimals
: Number of decimals; usually 18.
Example:
{
"name": "Sepolia Testnet",
"faucets": [],
"nativeCurrency": {
"name": "Sepolia Ether",
"symbol": "sepETH",
"decimals": 18
}
}
Alternative Sourcify sources
Rather than using the default ipfs.io
and repo.sourcify.dev
sites for accessing Sourcify, you may specify your own Sourcify root URLs in the configuration file by adding the sourcifySources
key and changing the URLs accordingly:
"sourcifySources": {
"ipfs": "https://ipfs.io/ipns/repo.sourcify.dev",
"central_server": "https://repo.sourcify.dev"
}
This is useful if you have your own Sourcify repository hosted locally, in which case all of your Otterscan activity will be private.
API Spec
This chapter only makes sense if you intend to dive deep into Otterscan source code or want to integrate directly with the Otterscan APIs.
Specification
There is an ongoing effort to formalize the Otterscan API spec in the same format as the standard JSON-RPC APIs.
- Online spec: https://otterscan.github.io/execution-apis/api-documentation/
- The repository is at: https://github.com/otterscan/execution-apis.
A more detailed explanation of the ots
namespace:
There is an experimental ots2
namespace, which is likely to change, but here is an overview:
Design Goals
Otterscan's RPC namespaces aim to provide a minimalistic solution for Ethereum data access which overcomes the limitations of the standard JSON-RPC API. Implementing features directly in-node eliminates the need for additional indexer middleware, databases, or dependencies. Our design prioritizes simplicity and flexibility over high-performance scalability.
ots namespace spec
The standard Ethereum JSON-RPC APIs are very limited and in some cases non-performant for what you can do with an archive node.
There is plenty of useful data that can be extracted and we implemented some extra RPC methods for them.
They are all used by Otterscan, but we are documenting them here so others can try it, give feedback and eventually get it merged upstream if they are generalized enough.
We take an incremental approach when design the APIs, so there may be some methods very specific to Otterscan use cases, others that look more generic.
Those APIs are implemented at EL-client level under the ots
JSON-RPC namespace.
How do I use it?
They are all JSON-RPC methods, so your favorite web3 library should have some way to custom call them.
For example, ethers.js wraps standard calls in nice, user-friendly classes and parses results into easy-to-use objects, but also allows you to do custom calls and get raw results while still taking advantage of their capabilities like automatic batching, network timeout handling, etc.
I'll use ethers.js as an example here because it is what I use in Otterscan. Please check your web3 library docs for custom call support.
Example
Let's call the ots_getTransactionError
method to obtain the revert reason of a failed transaction. It accepts one string parameter containing the transaction hash and returns a byte blob that can be ABI-decoded:
const provider = ...; // Obtain a JsonRpcProvider object
const txHash = "..."; // Set the transaction hash
const result = (await provider.send("ots_getTransactionError", [txHash])) as string;
Method summary
All methods are prefixed with the ots_
namespace in order to make it clear it is vendor-specific and there is no name clash with other same-name implementations.
Name | Description | Reasoning |
---|---|---|
ots_getApiLevel | Totally Otterscan internal API, absolutely no reason for anything outside Otterscan to use it. | Used by Otterscan to check if it's connecting to a compatible patched Erigon node and display a friendly message if it is not. |
ots_getInternalOperations | Returns the internal ETH transfers inside a transaction. | For complex contract interactions, there may be internal calls that forward ETH between addresses. A very common example is someone swapping some token for ETH, in which case there is an ETH send to the sender address which is only unveiled by examining the internal calls. |
ots_hasCode | Check if a certain address contains deployed code. | A common way to check if an address is a contract or an EOA is calling eth_getCode to see if it has some code deployed. However this call is expensive data-wise if the contract has a lot of deployed code. This call just returns a boolean. |
ots_getTransactionError | Extract the transaction's raw error output. | In order to get the error message or custom error from a failed transaction, you need to get its error output and decode it. This info is not exposed through standard APIs. |
ots_traceTransaction | Extract all variations of calls, contract creations, and self-destructs and return a call tree. | This is an optimized version of tracing; regular tracing returns lots of data, and custom tracing using a JS tracer could be slow. |
ots_getBlockDetails | Tailor-made and expanded version of eth_getBlock* for the block details page in Otterscan. | The standard eth_getBlock* is quite verbose and it doesn't bring all info we need. We explicitly remove the transaction list (unnecessary for that page and also this call doesn't scale well), log blooms, and other unnecessary fields. We add issuance and block fees info to the response. |
ots_getBlockDetailsByHash | Same as ots_getBlockDetails , but it accepts a block hash as a parameter. | |
ots_getBlockTransactions | Get paginated transactions for a certain block. Also remove some verbose fields like logs. | As the block size increases, getting all transactions from a block at once doesn't scale, so the first point here is to add pagination support. The second point is that receipts may have big, unnecessary information, like logs. So we cap all of them to save network bandwidth. |
ots_searchTransactionsBefore and ots_searchTransactionsAfter | Gets paginated inbound/outbound transaction calls for a certain address. | There is no native support for any kind of transaction search in the standard JSON-RPC API. We don't want to introduce additional indexer middleware in Otterscan, so we implemented an in-node search. |
ots_getTransactionBySenderAndNonce | Gets the transaction hash for a certain sender address, given its nonce. | There is no native support for this search in the standard JSON-RPC API. Otterscan needs it to enable navigation between nonces from the same sender address. |
ots_getContractCreator | Gets the transaction hash and the address which created a contract. | No way to get this info from the standard JSON-RPC API. |
Method details
Some methods include a sample call so you call try it from the CLI. The examples use
curl
and assume you are runningrpcdaemon
athttp://127.0.0.1:8545
.
ots_getApiLevel
Very simple API versioning scheme. Every time we add a new capability, the number is incremented. This allows for Otterscan to check if the Erigon node contains all API it needs.
Parameters:
<none>
Returns:
number
containing the API version.
ots_getInternalOperations
Trace internal ETH transfers, contract creations (CREATE/CREATE2) and self-destructs for a certain transaction.
Parameters:
txhash
- The transaction hash.
Returns:
array
of operations, sorted by their occurrence inside the transaction.
The operation is an object with the following fields:
type
- transfer (0
), self-destruct (1
), create (2
) or create2 (3
).from
- the ETH sender, contract creator or contract address being self-destructed.to
- the ETH receiver, newly created contract address or the target ETH receiver of a self-destruct.value
- the amount of ETH transferred.
ots_hasCode
Check if an ETH address contains a deployed code.
Parameters:
address
- The ETH address to be checked.block
- The block number at which the code presence will be checked or "latest" to check the latest state.
Returns:
boolean
indicating if the address contains a bytecode or not.
Example 1: does Uniswap V1 Router address have a code deployed? (yes, it is a contract)
Request:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '
{
"jsonrpc":"2.0",
"id": 1,
"method":"ots_hasCode",
"params":
[
"0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95",
"latest"
]
}' \
http://127.0.0.1:8545
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
Example 2: Does Vitalik's public address have code deployed to it? (no, it is an EOA)
Request:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '
{
"jsonrpc":"2.0",
"id": 1,
"method":"ots_hasCode",
"params":
[
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
"latest"
]
}' \
http://127.0.0.1:8545
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": false
}
ots_traceTransaction
Trace a transaction and generate a trace call tree.
Parameters:
txhash
- The transaction hash.
Returns:
object
containing the trace tree.
ots_getTransactionError
Given a transaction hash, returns its raw revert reason.
The returned byte blob should be ABI decoded in order to be presented to the user.
For instance, the most common error format is a string
revert message; in this case, it should be decoded using the Error(string)
method selector, which will allow you to extract the string message.
If this is not the case, it is probably a Solidity custom error, so you must have the custom error ABI in order to decode it.
Parameters:
txhash
- The transaction hash.
Returns:
string
containing the hexadecimal-formatted error blob or simply a "0x" if the transaction was successfully executed. It returns "0x" if it failed with no revert reason or out of gas, so make sure to analyze this return value together with the transaction success/fail result.
Example: get the revert reason of a random Uniswap v3 transaction spotted in the wild.
Request:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '
{
"jsonrpc":"2.0",
"id": 1,
"method":"ots_getTransactionError",
"params":
[
"0xcdb0e53c4f1b5f37ea7f0d2a8428b13a5bff47fb457d11ef9bc85ccdc489635b"
]
}' \
http://127.0.0.1:8545
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000135472616e73616374696f6e20746f6f206f6c6400000000000000000000000000"
}
ABI-decoding this byte string against
Error(string)
should result in the "Transaction too old" error message.
ots_getBlockDetails
Given a block number, return its data. Similar to the standard eth_getBlockByNumber/Hash
method, but optimized.
Parameters:
number
representing the desired block number.
Returns:
object
in a format similar to the one returned byeth_getBlockByNumber/Hash
(please refer to their docs), with some small differences:- the block data comes nested inside a
block
attribute. - the
transactions
attribute is not returned. We remove the transaction list entirely to avoid unnecessary network traffic. - the transaction count is returned in a
transactionCount
attribute. - the
logsBloom
attribute comes withnull
. It is a byte blob that is rarely used, so we cap it to avoid unnecessary network traffic. - an extra
issuance
attribute returns anobject
with the fields:blockReward
- the miner reward.uncleReward
- the total reward issued to uncle blocks.issuance
- the total ETH issued in this block (miner + uncle rewards).
- an extra
totalFees
attribute containing the sum of fees paid by senders in this block. Note that due to EIP-1559 this is NOT the same amount earned by the miner as block fees since it contains the amount paid as base fee.
- the block data comes nested inside a
ots_getBlockTransactions
Gets paginated transaction data for a certain block. Think of an optimized eth_getBlockBy*
+ eth_getTransactionReceipt
.
The transactions
field contains the transaction list with their bodies in a similar format of eth_getBlockBy*
with transaction bodies, with a few differences:
- the
input
field returns only the 4 bytes method selector instead of the entire calldata byte blob.
The receipts
attribute contains the transactions receipt list, in the same sort order as the block transactions. Returning it here prevents the caller from making N+1 separate calls (eth_getBlockBy*
and eth_getTransactionReceipt
).
For receipts, it differs from the eth_getTransactionReceipt
object format:
logs
attribute returnsnull
.logsBloom
attribute returnsnull
.
ots_searchTransactionsBefore
and ots_searchTransactionsAfter
These are address history navigation methods. They are similar, but ots_searchTransactionsBefore
searches the history backward and ots_searchTransactionsAfter
searches forward a certain point in time.
They are paginated, so you MUST include a page size. Some addresses like exchange addresses or very popular DeFi contracts like a Uniswap router will return millions of results.
They return inbound (to
), outbound (from
) and "internal" transactions. By internal it means that if a transaction calls a contract and somewhere in the call stack it sends ETH to the address you are searching for or the address is a contract and it calls a method on it, the transaction is matched and returned in the search results.
Parameters:
address
- The ETH address to be searched.blockNumber
- It searches for occurrences ofaddress
before/afterblockNumber
. A value of0
means you want to search from the most recent block (ots_searchTransactionsBefore
) or from the genesis block (ots_searchTransactionsAfter
).pageSize
- How many transactions it may return. See the detailed explanation about this parameter below.
Returns:
object
containing the following attributes:txs
- An array of objects representing the transaction results. The results are always returned sorted from the most recent to the oldest one (in descending chronological order).receipts
- An array of objects containing the transaction receipts for the transactions returned in thetxs
attribute.firstPage
- Boolean indicating this is the first page. It should betrue
when callingots_searchTransactionsBefore
withblockNumber
== 0 (search fromlatest
); because the results are in descending order, the search from the most recent block is the "first" one. It should also returntrue
when callingots_searchTransactionsAfter
with ablockNumber
which results in no more transactions after the returned ones because it searched forward up to the tip of the chain.lastPage
- Boolean indicating this is the last page. It should betrue
when callingots_searchTransactionsAfter
withblockNumber
== 0 (search from genesis); because the results are in descending order, the genesis page is the "last" one. It should also returntrue
when callingots_searchTransactionsBefore
with ablockNumber
which results in no more transactions before the returned ones because it searched backwards up to the genesis block.
There is a small gotcha regarding pageSize
. If there are fewer results than pageSize
, they are just returned as is.
But if there are more than pageSize
results, they are capped by the last found block. For example, let's say you are searching for Uniswap Router address with a pageSize
of 25, and it already found 24 matches. It then looks at the next block containing this address's occurrences and there are 5 matches inside the block. They are all returned, so it returns 30 transaction results. The caller code should be aware of this.
Example: get the first 5 transactions that touched Uniswap V1 router (which includes the contract creation).
Request:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '
{
"jsonrpc":"2.0",
"id": 1,
"method":"ots_searchTransactionsAfter",
"params":
[
"0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95",
0,
5
]
}' \
http://127.0.0.1:8545
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"txs": [
{
"blockHash": "0x06a77abe52c486f58696665eaebd707f17fbe97eb54480c6533db725769ce3b7",
"blockNumber": "0x652284",
"from": "0xd1c24f50d05946b3fabefbae3cd0a7e9938c63f2",
"gas": "0xf4240",
"gasPrice": "0x2cb417800",
"hash": "0x14455f1af43a52112d4ccf6043cb081fea4ea3a07d90dd57f2a9e1278114be94",
"input": "0x1648f38e000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498",
"nonce": "0x6",
"to": "0xc0a47dfe034b400b47bdad5fecda2621de6c4d95",
"transactionIndex": "0x71",
...
}
ots_getTransactionBySenderAndNonce
Given a sender address and a nonce, returns the tx hash or null
if not found. It returns only the tx hash on success, you can use the standard eth_getTransactionByHash
after that to get the full transaction data.
Parameters:
sender
- The sender ETH address.nonce
- The sender nonce.
Returns:
string
containing the corresponding transaction hash ornull
if it doesn't exist.
Example: get the 4th transaction sent by Vitalik's public address (nonce == 3).
Request:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '
{
"jsonrpc":"2.0",
"id": 1,
"method":"ots_getTransactionBySenderAndNonce",
"params":
[
"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
3
]
}' \
http://127.0.0.1:8545
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x021304206b2517c3f8f2df07014a55b79aac2ae097488fa807cc88eccd851a50"
}
ots_getContractCreator
Given an ETH contract address, returns the tx hash and the direct address who created the contract.
If the address is an EOA or a destroyed contract, it returns null
.
Parameters:
address
- The ETH address that may contain a contract.
Returns:
object
containing the following attributes, ornull
if the address does not contain a contract.hash
- The tx hash of the transaction who created the contract.creator
- The address which created the contract. Note that for simple transactions that directly deploy a contract this corresponds to the EOA in thefrom
field of the transaction. For deployer contracts, i.e., the contract is created as a result of a method call, this corresponds to the address of the contract which created it.
Example: get the address which deployed the Uniswap V3 Router contract.
Request:
curl \
-X POST \
-H "Content-Type: application/json" \
--data '
{
"jsonrpc":"2.0",
"id": 1,
"method":"ots_getContractCreator",
"params":
[
"0xE592427A0AEce92De3Edee1F18E0157C05861564"
]
}' \
http://127.0.0.1:8545
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"hash": "0xe881c43cd88063e84a1d0283f41ee5348239b259c0d17a7e2e4552da3f4b2bc7",
"creator": "0x6c9fc64a53c1b71fb3f9af64d1ae3a4931a5f4e9"
}
}
ots2 namespace spec
These are the docs for the experimental Otterscan v2 APIs. For Otterscan 1 APIs docs, click here.
All those methods are subjected to be changed during Otterscan 2 alpha period, so we didn't put much effort into documenting them yet.
They are briefly described here so you can have a glimpse of what we aim to for future versions of Otterscan.
There may be more methods added, removed, merged, etc.
Method summary
All methods are prefixed with the ots2_
namespace in order to make it clear it is vendor-specific and there is no name clash with other same-name implementations.
Name | Description |
---|---|
ots2_getAllContractsList | Gets a paginated list of deployed contracts. |
ots2_getAllContractsCount | Gets the total count of deployed contracts. |
ots2_getERC20List | Gets a paginated list of ERC20 contracts. |
ots2_getERC20Count | Gets the total count of ERC20 contracts. |
ots2_getERC721List | Gets a paginated list of ERC721 contracts. |
ots2_getERC721Count | Gets the total count of ERC721 contracts. |
ots2_getERC1155List | Gets a paginated list of ERC1155 contracts. |
ots2_getERC1155Count | Gets the total count of ERC1155 contracts. |
ots2_getERC1167List | Gets a paginated list of ERC1167 minimal proxy contracts. |
ots2_getERC1167Count | Gets the total count of ERC721 minimal proxy contracts. |
ots2_getERC4626List | Gets a paginated list of ERC4626 vault contracts. |
ots2_getERC4626Count | Gets the total count of ERC4626 vault contracts. |
ots2_getERC1167Impl | Gets the logical contract associated to an ERC1167 minimal proxy. |
ots2_getAddressAttributes | Given an address, returns a summarize list of attributes associated to that address, e.g., is it an ERC20? a minimal proxy? |
ots2_getERC20TransferList | Gets a paginated list of transactions that contain ERC20 transfers from/to a certain address. |
ots2_getERC20TransferCount | Gets the total count of transactions that contain ERC20 transfers from/to a certain address. |
ots2_getERC721TransferList | Gets a paginated list of transactions that contain ERC721 transfers from/to a certain address. |
ots2_getERC721TransferCount | Gets the total count of transactions that contain ERC721 transfers from/to a certain address. |
ots2_getERC20Holdings | Given a certain address, returns all ERC20 that have interacted with it. |
ots2_getWithdrawalsList (since alpha 2.1) | Gets a paginated list of consensus layer withdrawals to a certain recipient address. Note that 1 block can have multiple withdrawals for the same address, each one is counted individually |
ots2_getWithdrawalsCount (since alpha 2.1) | Gets the total count of consensus layer withdrawals to a certain recipient address. |
Contract verification
In this chapter we explain how contract verification works in Otterscan.
💡 If you are not interested in how contract verification works under the hood, you can skip this chapter.
We use Sourcify and the next section explains how the integration works.
In case you want to run Sourcify against a devnet or a custom chain not enabled in Sourcify's official hosted service, you can run your own instance of Sourcify and point Otterscan to it.
Sourcify
Otterscan consumes verified smart contract source code and metadata from Sourcify.
Sourcify is open source, their data is public and they host a public instance of the verifier.
Otterscan supports multiple ways to consume verified contract data.
To learn how to verify a smart contract on Sourcify, take a look at the Sourcify docs:
Integration modes
Otterscan supports multiple ways to consume Sourcify data, each one with pros and cons:
Direct HTTP connection to Sourcify's repository
Standard HTTP connection to the official Sourcify repository at https://repo.sourcify.dev/
Fast access to freshly verified data. On the other hand, it is centralized and leaks all addresses you visit in Otterscan to the Sourcify server.
💡 This is the default method Otterscan uses out of the box.
IPFS
We resolve the public Sourcify IPNS to get the latest known IPFS root hash of their repository.
The downside is that recently verified contracts may not have been added yet to the root hash and republished into IPNS.
It uses the public gateway at https://ipfs.io by default.
Please see our ipfs integration docs for more info about how we handle all IPFS integrations and privacy concerns.
Local snapshot (deprecated; soon to be removed)
☠️ This method is deprecated and will be removed in the future. The repository is outdated and kept only for historical reasons.
As a midterm solution, we are making available a snapshot docker image of their repository, containing only mainnet full verified contracts.
This would allow you to play with existing contracts up to the snapshot date/time locally, not depending on their service or IPFS connectivity availability.
The Sourcify snapshot is provided as a nginx image at: https://hub.docker.com/repository/docker/otterscan/sourcify-snapshot
You can run it with:
docker run \
--rm \
-d \
-p 3006:80 \
--name sourcify-snapshot \
otterscan/sourcify-snapshot:2021-09
Stop it with:
docker stop sourcify-snapshot
Self-hosted Sourcify
This section presents a short guide to self-host a local Sourcify instance.
Set up a local Sourcify instance.
Verify a contract on a Sourcify instance.
Setup
Run a local Sourcify instance on your dev network
Launch a local chain
Launch an Otterscan-compatible local Ethereum RPC node hosting your development server.
- Erigon:
-
./erigon \ --chain=dev \ --datadir=dev \ --http.api eth,erigon,trace,ots,ots2 \ --http.corsdomain "*" \ --http.vhosts "*" \ --mine \ --fakepow
- Note: The Erigon devnet only supports a pre-Shanghai (pre-Merge) version of Ethereum. When compiling your contracts, you'll have to set the
evmTarget
tolondon
for them to run at all on the devnet.- You'll have to create a full-fledged Ethereum test network in Erigon if you want to run a modern version of the EVM.
-
- Foundry's Anvil:
anvil
- Note: Anvil does not support ots2 RPC methods, so make sure
experimental
is set tofalse
in your Otterscan config.
Sourcify
-
Clone the Sourcify repository:
git clone https://github.com/ethereum/sourcify.git
-
To add support for your local blockchain, create a JSON file
services/server/src/sourcify-chains.json
:{ "1337": { "sourcifyName": "Local chain", "supported": true, "rpc": [ "http://localhost:8545" ] } }
You can adjust the chain ID
1337
and the RPC hosthttp://localhost:8545
as needed. The default chain ID for the Erigon devnet is 1337, and the default for Anvil is 31337. -
Adjust the repository URL in
ui/.env.development
since for simplicity we aren't using Sourcify's h5ai-nginx file viewer:REACT_APP_REPOSITORY_SERVER_URL=http://localhost:5555/repository
-
Build all necessary Sourcify components, notably the server and the UI:
npm run build:clean
-
Start the Sourcify server:
NODE_ENV=development npm run server:start
-
Start the Sourcify UI:
npm run ui:start
Otterscan configuration
To use the local Sourcify instance, you need to point to it in Otterscan's configuration file. In your Otterscan configuration JSON, specify your local Sourcify repository as the Sourcify source:
"sourcifySources": {
"ipfs": "http://localhost:5555/repository",
"central_server": "http://localhost:5555/repository"
}
Verification
Verifying through the Sourcify UI
You can verify contracts using the Sourcify UI by going to http://localhost:3000/#/verifier in your browser.
Verifying with Forge
- If you deploy using a Forge script, you should add the following contract verification arguments to the command:
forge script Deploy.s.sol .... \
--verify \
--verifier sourcify \
--verifier-url http://localhost:5555
- If you want to deploy a contract without a script, you can use
forge create
to create the deployment transaction. Create a folder namedcontracts
and put your contract files in there.
Here is how you would deploy a smart contract called MyContract
with constructor arguments 0x67b1d87101671b127f5f8714789C7192f7ad340e
and 123456
:
./forge create \
--verify \
--verifier sourcify \
--verifier-url http://localhost:5555/ \
--interactive \
--optimize \
--rpc-url http://localhost:8545/ MyContract \
--constructor-args 0x67b1d87101671b127f5f8714789C7192f7ad340e 123456
- To verify a contract that already has been deployed, you can use
forge verify-contract
. Here is an example of a verification of the aboveMyContract
contract example to address0xADC11306fcD68F47698D66047d923a52816Ee44F
. Forge can usually infer constructor arguments automatically:
./forge verify-contract \
--verifier sourcify \
--verifier-url http://localhost:5555/ \
--optimizer-runs 200 \
--rpc-url http://localhost:8545/ 0xADC11306fcD68F47698D66047d923a52816Ee44F MyContract
Public instances
Otterscan is meant to be run in your own environment (see install instructions).
However, we host some testnet instances as a showcase of our features:
- Sepolia testnet: https://sepolia.otterscan.io/
- Holesky testnet: https://holesky.otterscan.io/
Third parties
Test in Prod
Test in Prod, the makers of OP-Erigon, also host instances for Optimism L2:
- OP-Sepolia testnet: https://otterscan.sepolia.testinprod.io/
- OP-Mainnet: https://otterscan.mainnet.testinprod.io/
Ephemery
Ephemery has a public instance pointing to the latest iteration at https://otter.bordel.wtf/.
Commercial offerings
Some node providers offer their customers access to the Otterscan API. Please note that we are not affiliated with these providers, so you should review their terms of business:
- Llamanodes: https://llamanodes.com/
- Quicknode: https://www.quicknode.com/
Cookbook
This section presents a series of articles related to Otterscan which do not necessarily fit in the other chapters.
Running Otterscan on Pectra devnet-3
At the time of this writing (Sep 2024), the next expected Ethereum hardfork is Pectra and devnet-3 is up.
💡 This document may be updated for future devnets as Erigon becomes stable enough to sync them.
It is possible to run Otterscan against this devnet with some known limitations.
- Pectra-specific features are still in development in Otterscan. Otterscan should work fine, but EIP-7702 transactions may not display correctly or may generate UI errors, for example.
- It requires a dev build of Erigon 3 alpha.
- Caplin (Erigon internal CL) still doesn't support Electra. For CL, it requires a dev build of Lighthouse.
Get the chainspec
- Checkout the
pectra-devnets
repository.git clone https://github.com/ethpandaops/pectra-devnets
- Set
$PECTRA_DEVNETS
to be thispectra-devnets
directory.
Run Erigon
- Checkout and build the
docker_pectra
branch of Erigon.git clone -b docker_pectra https://github.com/erigontech/erigon cd erigon make erigon
- Initialize the chaindata with the devnet-3 spec. Consider
$ERIGON_DATADIR
to be the EL datadir.build/bin/erigon init --datadir=$ERIGON_DATADIR $PECTRA_DEVNETS/network-configs/devnet-3/metadata/genesis.json
- Run erigon as usual.
build/bin/erigon \ --datadir $ERIGON_DATADIR \ --networkid 7011893082 \ --bootnodes="enode://ff18fe4e41b74b76faa14b8f6070627d2600055b7c2c07eab18c33b78aaa7a1e6cf251743da9fec363e679a237e7a380155be9d87e5e9b7ef1249f383fa82133@209.38.242.185:30303?discport=30303,enode://ee7d7f43463297d97fa5875bba43892db814be0b67c5192c100deb28312e4678d996d86c4fcb09b73d904dccc485c8e8ecf3bc3edc4cd02edb1155cdc6da255c@164.92.203.70:30303?discport=30303,enode://c936cb7124853fdfc5adbef42011382f28d099b4a72c4681ed9716a1070c7d91d0a41c52c1e971ee3f0848e26c67980010426837506d7e4219e3cedd1d976566@167.99.248.153:30303,enode://a3c9e658072ab8c4efb078738d97bcd22b296f3dd977a35b3b6aa48df670a8c3b8319324488b204c49a2b799a6ae42b2ab02809951bfac9acb0e2969e7521c5f@165.227.165.102:30303?discport=30303,enode://594963a9985d2ef5ee219c64c1017c407c0e665b775ee8a6b68595ae2f5f53f6875990949678ec9d54cee00bb98c9e79e0d03a31695c22a77454fc43d4af7d42@167.71.61.219:30303?discport=30303,enode://929afd46af9ec14e6baca8ab78ddc301501a321cbdd5716a4df3f779777fbbab52beeae2c175adde7e962036969cd83c7cbca4201782a9c7f61c85ecdfcf5ca4@159.65.113.238:30303?discport=30303,enode://31ee342e249b9accc098a171a034545136f899c46ac8c155581bc699f7fcdabc8372f534b4db259b7fbfed369a5ad2e0fc6a5baebc7d70be1808799c3a1bf111@207.154.253.142:30303?discport=30303,enode://97ccc7f93a52b22a0dbe94e5a8482f68eca5cbdec21bbe9061a72c4e1aab41cc8a38200828e5f4a1db509a0a1ec431e2c5ba208ceb8b7c5bb06af9f24e0ebb10@167.172.163.43:30303,enode://19dbac34a3a0d97fcffad075a222ad2eb2c95913759b48f540db305c2c2910a60393ab96e18835d8c2a994bc5c773d339848a8b11441066834bbf5328c08400d@134.209.245.90:30303?discport=30303,enode://a0ea666286918488d36ab9e1dd06c2780e566a48474894246e0d8434915b8d5b161275e300907174b4b93f408e2681aa58afae8f4202a0ee170f7d37a1b3fbba@159.223.221.12:30303?discport=30303,enode://4dc25297111d77f3aa8f3bddbef5606b35e57efd6c4d11fb8bd64b0b7259436b0404f013e939adbd732ebb894c3e640327bbfbee70b0779ba4005acd2df9f558@206.189.21.79:30303?discport=30303,enode://4116e37a44e1d7c15f2b66c1d6b262b73d996bc39bf67ad84fa2b31957242b76f54e8204e18fc046ccdf214a72064aee47aa7be4dd583a17990b379b5fa27314@142.93.209.238:30303?discport=30303,enode://3bc854243c4a17c67b55c0339d46e20cdbc121dead795b6a1cc3f2e99f5402078dbc848b73b1ef55c56ce15e2e23d59ca164b205b61059dbaba451085ae672fd@144.126.220.230:30303?discport=30303,enode://0ad64eb3d40c5339280916e9802134ad97d8b4834d8530cafc91595a3c8b3ace1e57e2bfcd4cccc3dbdc622a6bf529aec5e8d8a1ff09d404bb40ecadea061d46@170.64.206.111:30303?discport=30303,enode://423e0236cb3d0a985ff64cc6fff1ef0ac85be32cd7ed848030afa42dbef28c9c66c93849c300e77ec5bb85bc48d528955d1f368158879d316f81ada6152be915@165.227.153.225:30303?discport=30303,enode://508d211acdfd5f8546261cc9a3a57994d1315c1a978e686a14a6daa69ad9fa8c38c3009e05327005594b9d4027c1547c7ecab6443bdb2681fac4e8027234a755@207.154.214.116:30303?discport=30303,enode://353ab4e06d50adb15aefbc406292d1bd164548127ec7fec0ea6e50aba94fab951140b77d14ccf6f69f94281b224f3ae9c5b3d3ac26424c84c57be87370c8cac2@46.101.140.145:30303?discport=30303,enode://6ef4f8403989cbdb27dbddb3e446c65e3ed280656f8c6d91fd4f2ff7e7911c80c3f6544a7c1fcc461c0b43b7001b62e487e32e5eb991cc26823b2c0a8d6bff28@161.35.67.216:30303,enode://4b809fdf0a1fe50e7e14e5bb2eede1991a5be561637af94ab5e6aca861688112f9529d26c9ce1e8899d4452b481b67c926db04310f131dc685084a1bbc9b7818@164.92.185.229:30303?discport=30303,enode://5a94a260ff96bb3ef9b80a1745272e3f9fadd9fd6635109a6234f25eb8634b2ead1685286be0f9280e16d82e2b17e745462cb3664511628f780c48b2603030ab@165.227.169.145:30303?discport=30303,enode://9be7b72a6928df50a77ac7b9885a83b73c4a3e6510fddfc728db7ac38bbf0f76bfef1ee0ba32179cf71ee520b8e2c8959286e3a16689542019939c67c899b051@157.230.110.242:30303?discport=30303,enode://80a795999356f9eed541d214c083b1a1dded6f8d0c49f092745d5f28c94b184bdfcdeef97d7e7702080b070945256a0e1983b4aa9fd4e45615513814c76ddc8e@64.226.89.31:30303?discport=30303,enode://c29f55177e16e65445262f15259b62cacca6518a1f185e3ebe9659b7205a05af91d74a5a481296c76e45c8383bb1c4c29fe12f8c4c92f8e2b87e98b5673b2c25@164.92.141.167:30303,enode://b3530cf2e13fcfab20b1a3f72d099bdb970ffdc29a08308418c596ef291b306e1eeac6868a1f76cbcc6d01d85206391607c6d458c35c5aa7214b5695d38a819a@46.101.141.131:30303?discport=30303,enode://4030dc9c14b0cf8e2dee47f2015b014963062c7e6887039faeaf377ee7c09f0f19946973b971b44b672f972ac1eaa25bb1faedb7ac9b0e66fe4be5b0cd880ac7@46.101.96.239:30303?discport=30303,enode://6a1f5cd24c920324267b4b2f19811f6e01017e8018e77ee10d4cbffad6f02102ee14ff75ef10ebab1e51af88582dca33cfc1983a63f6c26072ad32a34be3ac63@209.38.228.221:30303?discport=30303,enode://80c64bb580051177fc0f849882939e66483b026d4da1b1ca307721cbfba7789b64429ca1f871fc2f22180c825aeece86a08fcbcfbba247304314053834541eae@165.227.153.218:30303?discport=30303,enode://ba8bca3076e508d80fb6fb1eda641a0dfaf40e7b36dbbfe39550c9238b1e098f29d3449d2ab29ed3af3650309a9d7132135a514b4c81042d6aaf34b51f3de26a@165.22.94.213:30303,enode://2aed8046b67279046109473dab173520882b4a8e78ab88173064bad8af7d2e36e122593ee54db79636099dcc6cec22f66970c37017a34953da5d32091cd9eb27@159.223.16.43:30303?discport=30303,enode://5de20a20ed93faa30dca8ea11c0e4c8c81414c20004a196733f506ffef9559b874e15c9fc6aa80cfdf2ef3d51b9922be94eafa0be08040d858aa88c64ae40b85@161.35.89.132:30303?discport=30303,enode://a9d816fabf48075cef072d14b8c55ac5e6a435f2126dfe77414c9fc7a2415f1f957cddb275683c887056449e40260ec38155619bfb5373d13746289d81a56d19@209.38.164.8:30303?discport=30303,enode://5f9ec2e85ebd646a9d40c60e0827b08a67add8be2f070a52cd79e469e85136d178387c9ba83810f45ea03d247fbe8eadfeef3b55ace60ddc3fef90f2d12323db@64.227.160.6:30303?discport=30303,enode://cf83258050e2de79d84c00048fd1921e2696eac931fca715c1b137c617f79a96db06ab86c6c5b9d5df7bc5cade9bdbe2f511ecb12ccf72d8c8572322d9b2ed7e@143.110.152.53:30303?discport=30303,enode://c746f68fd154d5452c79f373818d421c4845517ef81acbcdc7c1ba406dca7a9d11d01b5fd68115a62534cdd3b6bfb25e64ee31e4a6935197a491f30b4a638973@170.64.191.178:30303?discport=30303,enode://c28d15fd697493aadc201babed7b492cf0ea5486a011014a05048511816735bc1357330fb1b0c3a5df120d5e3c210894cdf18ee21af7b1da19d1f664884bc3e7@161.35.22.150:30303?discport=30303,enode://75196a118fc1cd9ed57be21f8e0e28560ebe338870d18d813c56aec82792216c2a5eb6e863d6fc45cb3235d9ccfdd66e452e983a929c8b272f22021b8c7d4d78@64.227.114.235:30303?discport=30303,enode://14fedd050d69d45a88bb42fcef3a9f579673326a69bce20856cd50097ff9228fde5e95c2c495c7bf712f812a6c3c5a71e4aa67ff58748cbd45eff719716e78fb@104.248.135.247:30303?discport=30303,enode://446941a7a1e3a884ddee74b72ca7e28524004b5740075e87dff565c949a8b0860cd86614faf7102ffbf7f2448506b90acb618d9e6417658a99e4e2364d3c0b21@138.68.73.9:30303,enode://d7493068bb71ae30561166c5964cebad13a9190b53d31edaaa82a78f938bc87d6b744efa0d493a2fbfc11ee5238a028e1f60fce7978631c3d992721440e0f8e2@207.154.214.127:30303?discport=30303,enode://c3423c7f56a199a0e31f78fa9f3e31db8e6c8a81e4ee6a40e96180a04d07e8dfb185caf7447ff1b842fe44a1f2cba3cd73a818ab12a31009fcea2cc9d597a17e@167.99.37.51:30303?discport=30303,enode://9fbbc9b3b6bc15d3615efbf076803ce92ae947f72ed3bb548efe62a0c602104eb1889c8fde40b100b32a16106fde7df8e8b4f5c1be3e5bcddd062e8563480532@138.68.166.32:30303?discport=30303,enode://546d77f608eda362b831e319f5f86af4b26793a93e9bd464881fa9911322ed8889099f1bfdb4694abd45689bd47716e26ecf8c5539824d4d6cbe55731344c975@128.199.21.177:30303?discport=30303,enode://12d5a619b426b73c332895b143d2e8f34000845daa121dbd22f97fd1ba72e0901493c5cddd9b6c59d36cf27d89c58d05a88c3e100634d841dc9a8e6d754309bb@24.199.118.171:30303?discport=30303,enode://22a4bb02de3c1baa0509d03f5fb122b123a8a225955b3201bb0492f73f76e66299b716194cee852ab0a347a717506327cd35d8003cad17440228a94506b01de8@209.38.24.26:30303?discport=30303,enode://5348e1cbc8f9962fbedaf08a1466e6890ca1501f6f7b4bd28304934948fcc8b04acaac776cc06460884559921f6f82d1cb2c5090a8c46d29ff32c82b8ec4e148@207.154.199.155:30303?discport=30303" \ --externalcl \ --http.api "eth,erigon,ots" \ --http.corsdomain '*'
Note: the bootnodes are taken from here
Run Lighthouse
- Check out and build the
unstable
branch of Lighthouse.git clone -b unstable https://github.com/sigp/lighthouse cd lighthouse make
- Run lighthouse as usual. Consider
$LH_DATADIR
is the CL datadir.target/release/lighthouse bn \ --testnet-dir $PECTRA_DEVNETS/network-configs/devnet-3/metadata/ \ --datadir $LH_DATADIR \ --checkpoint-sync-url https://checkpoint-sync.pectra-devnet-3.ethpandaops.io/ \ --genesis-backfill \ --disable-backfill-rate-limiting \ --execution-endpoint "http://localhost:8551" \ --execution-jwt $ERIGON_DATADIR/jwt.hex \ --boot-nodes="enr:-Iq4QH9YP9c_ZBYZNAGJpeAp8bHo2at4Xxlv9346r6jcN2M1HOTJzyIcT55UivXY28xBRHpaur4-mmsx-ac9IozcxcGGAZHg-RR9gmlkgnY0gmlwhKEjS0eJc2VjcDI1NmsxoQJJ3h8aUO3GJHv-bdvHtsQZ2OEisutelYfGjXO4lSg8BYN1ZHCCIzI,enr:-LK4QHcwaTAj-IHTdgb2468cyWcOvwe1w5v8a70g6H-rwecXGqWMDaWJhaHk5CX6zabkWxZN534FjJGJLzqQwpREFnQFh2F0dG5ldHOIAAAAYAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKEjS0eJc2VjcDI1NmsxoQJGSG1iaWxtD7wAKUwwL6N1ZP-L5ZSoxOG0UFxu7ZO-sYN0Y3CCIyiDdWRwgiMo,enr:-Mm4QMK3bYqJNCGe3MQtnYQq3VKlQSyyyIf3YYElyxUyDC1PIctaPOwvhKL9BWFzo5j4-XQ6bEx6DBQF8cpQvzllq_kEh2F0dG5ldHOIAAAAGAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCE0SbyuYRxdWljgiMpiXNlY3AyNTZrMaEDj7zD5JDPNJkalSpukdLnZikjS9NoLBxEL_pCoGmchbCIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QBiYB_dqgCIuzQuntX1QJ0ompnQesuG76kzt41dz3K1iSx-xAvRq7Mr6_vVZGcj3RgrGMY7SGb-j0Ns-Kq-dAGUEh2F0dG5ldHOIAAAAAAAAAAaDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEpFzLRoRxdWljgiMpiXNlY3AyNTZrMaEDTnDF9m2CDL51ouYIc3wBPGYjCg_yqKP2EiaIn45LC6OIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QEesrCH4Kpe7uSNmAgwsTjDr1X796LFMdhYWmS6SLcujF-UknSDUEOJ-dymGBAYaWhsgesbRbE78ALic1bV37pwEh2F0dG5ldHOIBgAAAAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEp2P4mYRxdWljgiMpiXNlY3AyNTZrMaEDCo_1OXqDsG9ETOi8cZ6iSylpMmxqYUXB8s4vfXAo0qGIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QIGJsArPpB7jrx797b-L3YtcjnkJXKDKMvwQ8F8M4DXURXeOCmUrofHu_XmiYAm5uKtfYnrqRxsuULXKwez3HuQEh2F0dG5ldHOIAMAAAAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEpeOlZoRxdWljgiMpiXNlY3AyNTZrMaEDUwSln3m97ldBcHhH2bGkfwihfUWb2SPdyQV8XVLWnvSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QLsPYu0a1FVXdjwmWxCUEV5CEjj9gwW47bi1NC6gOK3IaoNgrKrtvc7I_T5UuwHdlkaSYqfvIk1YLUi-iuGsi5sEh2F0dG5ldHOIBgAAAAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEp0c924RxdWljgiMpiXNlY3AyNTZrMaECoAsFP5EJ-GSz9o6dtJbSB-ULdjphFi3brdyx1QfA7bWIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QLPeqXNPNg18MMmeuuqEYYWaS30KDrwqEL2gV8sUNXdKXd3VkwReQ-1SZ5TGkqTAOfoHMRwt0fZRBlxRnQOA8dIEh2F0dG5ldHOIAAAAAAAAYACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEhnpe84RxdWljgiMpiXNlY3AyNTZrMaECBIcRRir8-AAvet_y_6RJ9EPw16V_UUw_3yMANOh8XQSIc3luY25ldHMAg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QNd80QG-lLQMjY6wNDQNBKjLbRWvczDzvQx7VVGrMzpoeG27y59OjwhkWAIdYnbgyP4gITH9d3cg4crezUT3afgIh2F0dG5ldHOIAIABAAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEn0Fx7oRxdWljgiMpiXNlY3AyNTZrMaEDm2s7GQJ7LJXgSCp0mkMWJwu-fKVPcI7umazrmh61dmuIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QD8SJ3WvRuG2i8effDaqvMhkbmiTWsLK2rCU5EaPMCW7P_l2IatxdsTLUrSxS5bSQmINohm07-mvo1TVWCymdikIh2F0dG5ldHOIAAAAAAAAADCDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEz5r9joRxdWljgiMpiXNlY3AyNTZrMaEDLU7_CmCPjnPoA-GODszqXyOEogLlnKIMUG_o29yCwfqIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QIwoESRrBq9hz9ODJGfypT9VWS5dcKjbY_ahlgsC0P9bdwpZfW4z0ZPCMNY7wHwSejHdUt-MgFzZ2coSBK5oMdUIh2F0dG5ldHOIAGAAAAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEp6yjK4RxdWljgiMpiXNlY3AyNTZrMaEChgY4sODpLFJRwg80XXL9AHTHUYOzvsffRFIp9vhHilWIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QAbBEqLrqLbogLL3pYc9vOulTluk-ly0rhJOiyFPm_8WMu9t7A3-5CoY4XXyEl2jzvtWyAHBQjwtGgYde5S-N1IIh2F0dG5ldHOIAAAAAAAAGACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEhtH1WoRxdWljgiMpiXNlY3AyNTZrMaECJXj2OCPwk7RhEw8Cuxa78O6RO6KCLFNCbO2UDqxJC2iIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QM5fQpzJISCo7D4ZcsbxfAajJlWbqKrkhLcumq1w5tFLdal8JH7zbEuiENEUxuVYHULLaWa8NbhSM9qlrvw9ml8Ih2F0dG5ldHOIAAAAAAAADACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEn9_dDIRxdWljgiMpiXNlY3AyNTZrMaEClUjHxH0euOihEDlpGV77WNBAK2u-oAYWN56nhI-yqDSIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QD0qgam1Ol2K346338i8Fhzoiml4I8u2o6LZRoyuz0fZKFNt4xbBCudEU53nnfDll3agh02IzFPau5YZPauFpKkHh2F0dG5ldHOIAAAAAAAAgAGDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEzr0VT4RxdWljgiMpiXNlY3AyNTZrMaEC-Yf7GuxpT3ImxHaotc6EO0yj3s51ors2P0U3EjvTFzCIc3luY25ldHMOg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QL3jjIRRlWPqr9aDJnWD0Vec0CazOqNqjrhtTOCwK_GULjSjOQwfPmEIeWIWduiYuXvo4a3aL9btsUWvB48H0vsIh2F0dG5ldHOIAAAAAMAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEjl3R7oRxdWljgiMpiXNlY3AyNTZrMaEDYFwh_4j07AsiXv418uqGD5aW3z3Uvakuq8uws2v134qIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QIEd7ToKDICIOOcqw9pPDwdPyygxOYgtshLyVbh5CY4ANGldRGMQuu3bHfLdSD90Qtdm9wpTg9-DGVfdujMi9NMIh2F0dG5ldHOIAAAAAABgAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEkH7c5oRxdWljgiMpiXNlY3AyNTZrMaEDi4-6GEX-ad5RFTgiWzHhf3_HFMnS4IGB71AUXPX-C5-Ic3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QBn_4Y0CebUAX6KP2nEiyFWqukn1b2q6B7OGgWksAgZSU7buuzUqmwNlPfhfS7KqHY-ah9rlj4kL7w_XaWlZOLkHh2F0dG5ldHOIAAAAYAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEqkDOb4RxdWljgiMpiXNlY3AyNTZrMaEDJJzxbJwvoud2-qV0NO3cJ4H_Qb2v4HfT4D15BwEB0n-Ic3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QIsuAUU6TT5oY7Z4vs2H_0UmyF3V8HZrIPaiXDTEuqEPBk_4oC169-ZMYMHhtagOm9GuMcMCuCDoY8n18AfrsH0Hh2F0dG5ldHOIAAAAYAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEpeOZ4YRxdWljgiMpiXNlY3AyNTZrMaEDU_dPSt7zhPfa8yPCUcgOcDMRSyLxaekcEzohEwb45JOIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QCJ1VkqRvuu_2Muh1EoGrw1GVoBIIEKAZzrzYOoUlupBfc5G84G1m7Wic-Ijsy5UhzTypEElHw6HNDtjEyTiGTIIh2F0dG5ldHOIAABgAAAAAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEpFqnF4RxdWljgiMpiXNlY3AyNTZrMaEDJRSqbsdJkB9M_I6WXQ7ORGYDn7SkckHwmNGslx4nKuWIc3luY25ldHMPg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QA_VJo5-6JzU46NV_K7Wk5aB6-Pp1yt1c_4v1gg715-ha9DfvOG7eCcVvNl0D8L4ITZBir4qGspGiD4oUFHRF3sHh2F0dG5ldHOIAQAAAAAAAICDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEhtHHIoRxdWljgiMpiXNlY3AyNTZrMaECVmo4zAZk7GnXoc6vg4OLn8A1W0GgNI-OduRu3FBxb1WIc3luY25ldHMHg3RjcIIjKIN1ZHCCIyg,enr:-Mm4QAs7SBg3KgJI3UtRJSvSViPwz1UIbzmUKdwULme-se0iQsuFItQCxyl3wXjm5iLn3dd2_zj9oSKsMmHwWO30IPMHh2F0dG5ldHOIAAAAAIABAACDY3NjBIRldGgykP6frPVgIWIo__________-CaWSCdjSCaXCEhnpkk4RxdWljgiMpiXNlY3AyNTZrMaEDN3fR1A71Izi6b0ItqEZ6ewWPO-Ivm1PrDShC3Vbms5GIc3luY25ldHMLg3RjcIIjKIN1ZHCCIyg,enr:-Ly4QHCunWAHny5krOh_mkJtnfGOcLxig9qYT3M_jaWmv0GbcbMx-FhhI1sik3MCRCGh3kljEiLJyu6XdqW6Tk2Z9iAGh2F0dG5ldHOIGAAAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhM-a1nSJc2VjcDI1NmsxoQJ2kaGOVz1ZrFe1AzhGyoQIwfF5V4J-xNBjVfO5QEcPEYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QPxLB54OUtVB5YNUfDHPbMAxE8TFi5AJiRUcL_M4S3KvSZ-eSLb6rUpFTLE8PKUVDAfwGJv3uy4VCCDF1edgh8oGh2F0dG5ldHOIAAAAAAYAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhC5ljJGJc2VjcDI1NmsxoQJe6maziE4vCEI0WjXDVv6O1e6FMUn607D82sH2DhJiEYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QB-4zoObs7jHXc8a1aed3JxRQNnL2dL16UWkd31VtY0VN2c9V_lnZdNJ4rWpq7Z-I3AZw0K9cC1j-Dg36m6PL_EGh2F0dG5ldHOIAAAAAAAAwACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKEjQ9iJc2VjcDI1NmsxoQONzoFh_aCVzVtVpBYV3rp6cUs9NtPw2KSbopbVvbM2bohzeW5jbmV0cweDdGNwgiMog3VkcIIjKA,enr:-Ly4QOukBAUfgTYutX2srxsnoBTS-nkAm79o2HMxn0ytvq0NO9z7if8swDTMHo7XD9Mo0cg8oW1_8lHY_5o-Q1nzNwAGh2F0dG5ldHOIAAwAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKRcueWJc2VjcDI1NmsxoQJv2WXVrYuNrAtuiVDUBbsb9VbYUz-YcbBdrIK1mfCAIYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QN6APohnbZ8ePtZy0Vj1MGx-DGtVXfbXB7as4TJDFJi7N1OBsttbbNjALNFumcAI5W_n-rwNf7-0uzco5uocbzsGh2F0dG5ldHOIAAAAAwAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKXjqZGJc2VjcDI1NmsxoQPRqcRzfYcAwHOEPxPXUlp0Gk84NByOwdXNkiov1aYWZ4hzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA,enr:-Ly4QCLn9JyYPnCXGfG4SgD5iak85ITYJLchYVd7sGuWro03eU8VI0WYI9e2-g2Wuo2RSfWCgUIio8DxL9pIWWtMFsMGh2F0dG5ldHOIAAAAAAAAAAyEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKRc6_WJc2VjcDI1NmsxoQM8-d1r2yhZXyovSCNbnnXyyyq9XcqgO9o87YDdbRsCQ4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QHPrLSKnxIFgWr9-T2stC5SRKovZHeN9Yc7Uy40-U8iKaH2S6YTDN7idj0mgdCVfrkuud49AzARO0B08iCZMveUkh2F0dG5ldHOIAAAAAIABAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhJ3mbvKJc2VjcDI1NmsxoQKR-IoUBcqPvwi8uRGigNQNshtYauc66gko_vsia-Xx44hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QLL5zzSAkvkZgT9pucH1V0qe_AUnFcV_z6GhTP5KBs2Hf37L0h15KUcrdGx2stYnqbwyJwYiXRVr2oFGcogPs4Akh2F0dG5ldHOIAAAAAAAAABiEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhEDiWR-Jc2VjcDI1NmsxoQMC3AEHcSnAq_6fCXk-69_7QRBe91D6Ak2LzPdDycsVI4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QMLXCEO2Whkh2g6Z9McmpWGHU3t6_J__dttNB1_1cbScUlGU85FXtxPgzfNG2vSexbfG2huewnyn_pxAwj5O5gEkh2F0dG5ldHOIAAMAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKRcjaeJc2VjcDI1NmsxoQN6ytBD7wl6RxboHaOIGBEYaWhHzZFtkJb9II20sfEHaYhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QImBbavEify9WpKR5ecPdISd9_VdAaCJzmFgQl5oTb3wexRePHyP7uIgpvh_eOGDXqqsIWQTEZcgn12onsVPZz8kh2F0dG5ldHOIAAAAAAAMAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhC5ljYOJc2VjcDI1NmsxoQJVqCFRgfbYCUhS8lMRGcihvKMLarznHIGGat1CRWVGD4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QN7De81bi8bry3gqJIBHzw1oJcAkmIwBBrBFVB8o94HiZKZDTZBCdCcsAb9bKwMd3GPF0I5zrkLxbzjWCgUQeyEkh2F0dG5ldHOIwAAAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhC5lYO-Jc2VjcDI1NmsxoQO2k-9mrLGoBDQaHf09AHJsaNNQ-SimOcF_QvgvOdfObIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QM16sheh23CS2e0yANx-5pKEEpn86QDuCswnNEYAS3nVWrGRI88FAnNm2uIEzpUnuPcr6rR2Au61g6Ydd3tMUhskh2F0dG5ldHOIAAAAAACAAQCEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhJ3mc3yJc2VjcDI1NmsxoQM4wLPTJcXMDSbkmRkiUdYEGAg5JcoN4v7UfEs7FrNg1YhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QFK8DL1GO6X6wfc9TBxonNrSkTGSWdRJqt8zPA0r_rkkDAHi8SGZZp-NdaJnbStoDDcVLvf-w467vqRw22XIBZ2GAZHhBGmDh2F0dG5ldHOIAMAAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhNEm5N2Jc2VjcDI1NmsxoQJVOWjZ3b6YWbWAKeNb6jIIuzP9014H_MexSg2v4RdwTohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QAoNGB5EcDtSSDPwIT0kRQSa7JmwLIavrm-be6kqrevsISkKXf8ITv2vApUXpkkYApabr3KSLDjqSF1R8KrZ5vuGAZHhBGxRh2F0dG5ldHOIAAwAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKXjmdqJc2VjcDI1NmsxoQP5wJZ1KfNQ-Cs1sc4z2Drp53FcvxKM2iw1cehs1JrVMohzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA,enr:-MK4QDbEOKIvuf8kibpRk4pX-pwULgdgacGWev-JFj7eRHKGCitPzAFEV4KuIFdUaVuPRXuy-51mopt0hsaSG2eEA8iGAZHhBG31h2F0dG5ldHOIAAAAAAAAMACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKUWXtWJc2VjcDI1NmsxoQJ0-yIZwTM6a3nYNtwP09jRlv99ycteba0Cy4YWdHeS-IhzeW5jbmV0cweDdGNwgiMog3VkcIIjKA,enr:-MK4QL7WHb0FcSD9CvPxtOWh85zCGks3Ajk0vVXq-lGHQuEpXYm86QXLztTywUmLtv3gwNCdrQtJRqaZZaoUVS4k4GeGAZHhBHBKh2F0dG5ldHOIAAAAAAAAGACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhJ_fECuJc2VjcDI1NmsxoQI6nELvuF2U1ERTTMtnXbfmZQ50QwzBm2AdNjWYcHC24ohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QLV2R-5BfNy2Df1OqfEfiQ-D9p6yKFNDrUQtX_dkKoOeTsdG7QtcCv8LgLKnU5yjNf8mhuOoayedEp8ox4wCqpSGAZHhBG1Kh2F0dG5ldHOIAAAAwAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKEjWYSJc2VjcDI1NmsxoQMcke-W3i7ODVZnbq28QVnNVDbMmB5BhYlTDaDgaW3Hs4hzeW5jbmV0cwODdGNwgiMog3VkcIIjKA,enr:-MK4QLN8VNlJlbFqe9Ksm_TixvO46chZ4FRY2LhMPcdP9VepZA3bTDU4CIGiefkxZl5OMMg5PtHM_6Xh3Cmf3AbdTTqGAZHhBHD_h2F0dG5ldHOIAAADAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhNEmpAiJc2VjcDI1NmsxoQN4LkIjmL5Lny2E4FqsC9CEsvPxwdT-jJzk3OahCsy2XIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QK32AybiWTPF7-ckT509XAfOiYp_EsijsQEspb5zCtZwe5WUBCAFgttyKb1YS6waWxr0KwvqC2SqfFvr1xFsG4qGAZHhBIooh2F0dG5ldHOIAAAAAAAAGACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhEDjoAaJc2VjcDI1NmsxoQLsLkYc19PN0b_L10d0irdD5Iub1R2smGP8bT3FAvFFzIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QGHXDg-xkB8Kk_nutvItkA4hJH-CKlno0qLHgU9Vzdz1WI0KzdIQTHGdZYozHX4pAgIb9eZSfwC_SS-lUx-4brSGAZHhBHIqh2F0dG5ldHOIAAAGAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhI9umDWJc2VjcDI1NmsxoQI0k5salAEXHh_ohq0WLfBBG2Rk_VR3ZJBPqGopiljIoohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QFHEpQU7I7ObmjOE7gTQquk32Zte9YImMFlaogUYyptwHmMVhoTOzGUzWtzwkiFVE23J6BhqAfvaj_fvLVjyQMGGAZHhBHkSh2F0dG5ldHOIAAAwAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKpAv7KJc2VjcDI1NmsxoQMiGgGQkdf7ulLLO1_srqzvQDgswbBGvmnHQLBGCHxOG4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QCCbBzLP6meImuRrr8cgA10_gBFCOBV4MRUN2f-jUuNjJkcrpKQkhfEffEY4UBejQOifENEFbHytAKqTK-n7TgKGAZHhBG_Zh2F0dG5ldHOIAAAAAAAAAAOEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKEjFpaJc2VjcDI1NmsxoQK-w-nEbdGb1f1eEGkXmNDoR1JFKS8Tw41JlupzrP6ln4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QAnqsZguRBjctIorvNRLyLoJQvz79WyckEbShBrSU0NjQyRMaIlnLjinEDgxVjD1YUu8c3R2KJkehzh3QfeMiPWGAZHhBGn-h2F0dG5ldHOIAwAAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKRa4zWJc2VjcDI1NmsxoQMFJ7mS6v1h4PUcwmDUHfUtEuSHM0seDsaKQ4CmM29fpohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-MK4QO1_z3egFfaP9mVfa9MNHqr4uiBItOAimxcJPNUzc0WvE2DOJzz35iWgDTvX7Lykd8KRMUdgsDObusFeOOQCsrCGAZHhBGq1h2F0dG5ldHOIAGAAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKEjV0WJc2VjcDI1NmsxoQIJSQjZEVdAyhaEQN7yfvhBVg2oVGyHtq9XfSs4y_mnuohzeW5jbmV0cw6DdGNwgiMog3VkcIIjKA,enr:-MK4QM-gKq0sM0LUDQPgJfaLAZDLMQQpjRlUqVdL-HqTgdJhZfSjEj4_qNmqxOQc0HesgrX_PNMJqvkXJPR39tDsbzKGAZHhBHVCh2F0dG5ldHOIAAAAAAAAAwCEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKdjweCJc2VjcDI1NmsxoQPicbgqSK8hy4_kzSpcJ0cT6Q2Um1BIyqNlbkv0Bqoxw4hzeW5jbmV0cwqDdGNwgiMog3VkcIIjKA,enr:-Ly4QOQxOoVU510wme5T0VB6PEPiSXoLO2CwRmbG-q5TGOvxBVI7h7b_JHkLx-R3JFwrEnJAKWEVKUIc3lM8w3WCencJh2F0dG5ldHOIMAAAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhEDjcuuJc2VjcDI1NmsxoQNC4GPdsRwXf-6qbX4HjRjIW2SSJdpoxsfM9BdCW8JT2YhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QAZHOo5OSQKKDyyMhChlxV2PfaceYkgP-0nZuEdOVTN6RGK5jY1Zo08Gh7ulgaZniPdVl1rI0RbVTaF4ZR7y0ekIh2F0dG5ldHOIAAMAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhGj4h_eJc2VjcDI1NmsxoQOMgoYfjt6S4CpsIGDV0VlsXr804pTrfXITLMwFraYDE4hzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA,enr:-Ly4QDUn5ntsdIeEM5FRJEpk1HKO5yUgP_S8UHM8uYyUcjt_P7M9D7Y0Gc3AYfvXnVs3_swbPJIDcBkwTOjSXZp0ac8Lh2F0dG5ldHOIAAAAAwAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhIpESQmJc2VjcDI1NmsxoQIj1hDqf6kfvbUEaJdmpaZp2ID1rIf7iDOVRnN0FHkbXohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QGy7qD0MndiJzoA3Amcoec5loLf29vUo6FNnF6U2uCDEHoCirAUgUaClFCxkDVt2t1XVtJe0pfns2vsiOVnR_iYJh2F0dG5ldHOIAABgAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhM-a1n-Jc2VjcDI1NmsxoQN4y2XWAt8YHTf4nBTDvFQpvnTRx8aXw_k-dfnUrbvkn4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QH0LJOPhjZ-FUxLcdpvDAif1wIvu5uLNxjVsrh3NdvrZGEXyOWscuG1CwgZX4lBCy77HGtMnuX9o_UKYLRHaWa4Ih2F0dG5ldHOIAAAAAAAwAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhKdjJTOJc2VjcDI1NmsxoQLSzwnWNOk1rLJNmBlQ7HtG64HerMOF8PZv1JpYnhgRt4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QCOsHEfic9_uIfwZ7Z-rIEvSMvHbUs2s46IfFOCtSA_ZBxnWX0BOH9L3iBBOtH7bqKAmtjTRw8t3oLDZJD7smCELh2F0dG5ldHOIAAAAAGAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhIpEpiCJc2VjcDI1NmsxoQL7B1-_c9PS33Hubb7f4iBpSSwNfa1Zj8qccbF-bNRKE4hzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QPTschBTWG6LbjvJvJow_kjFYlXV0hCpTuYmq3bsSTQLKc5XdSPWtnX9COt8IykceA1exUNhpVISGSMOESJPaIwJh2F0dG5ldHOIAAAAAAAAYACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhIDHFbGJc2VjcDI1NmsxoQNLTg0heNWKp2p8El496Iygr6-SWWIL3q9zu6mm888HMIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QMeh2EH9N12NzPGQpcgq3lSezorQ9yNm34q9kXQLUr5Rb9SnrO3nu3jwaheb0EN_cfssctvTgmgmxKED_0MeDIYJh2F0dG5ldHOIgAEAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhBjHdquJc2VjcDI1NmsxoQNSCaj6PKm81EaOpvyRncsGuglVFkJjGDOzq6qT5tBW-ohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QFZZrKBw5HYQz0VmpPyoj2zyxFKezXpL0JWQCEGxg9s8ZyD9zzC0nn8HB6XwAkpIBdBobZ8VPHzdWXVHZVy73Z8Ih2F0dG5ldHOIAAAAAAAAAAyEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhNEmGBqJc2VjcDI1NmsxoQItWpunYuwzPhlbKBw2S8TB89p8kpif3XaiM5NHXQeTuohzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA,enr:-Ly4QBzBE5WqGd_ZSCv3p8UnxFWfewtKRSRsutl3sNb7MqUuJjM7ixvrnfkXVAq_xrBUN9eiVItyaVGQwUNPHlxQr94Jh2F0dG5ldHOIgAEAAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhM-ax5uJc2VjcDI1NmsxoQMkOV7Vs7V8IR4S258CqUh-EXt8PATnpGIt9yZb8k8nhIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QHZ5nVoMmeiEmTwpI9m00R5fiEuhUJskbfb8UrOsqtmJOqk95CB8L0-jNu-Lz8H26ygDO8cbmaUmoT7AZZIu8GMJh2F0dG5ldHOIAAAAADAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhGj4Eq2Jc2VjcDI1NmsxoQN5WN7sAfpbCDMJ7Xo943jKJUIXHvGAf4LyGhYYYa_7KohzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA,enr:-Ly4QHx0UWL0QpoV-_1NJ0H8UNAHmWqHx0Myya4d0gfSNwh3QAY7RHDkdWBHKeLWjjWyHuNhtb2sAyqbDm2C0i4lJFcIh2F0dG5ldHOIAAAGAAAAAACEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhLKA99uJc2VjcDI1NmsxoQNwXxpcra9CHQWa3iX3mqjeapdJff2DZfFEgqmytGlJhIhzeW5jbmV0cw2DdGNwgiMog3VkcIIjKA,enr:-Ly4QDWXNYWf1G72sFAuya70AbSUfqjlOlQfc8FeFQHrlBb0ENDkhZcAIQKpQc6OT6LVlsN_fdseJPBHYIcK3HP3_FcJh2F0dG5ldHOIAAAAAAAAAwCEZXRoMpD-n6z1YCFiKP__________gmlkgnY0gmlwhJB-4rqJc2VjcDI1NmsxoQN9JOOkjKxDzd-lgSeSR7Jy74b7_uwx00iO3eyvF-CySIhzeW5jbmV0cw-DdGNwgiMog3VkcIIjKA" \ --http \ --http-allow-origin '*'
Note: the bootnodes are taken from here
Run Otterscan
- Run the development build of Otterscan.
docker run \ --rm \ --name otterscan-pectra-devnet-3 \ --pull always \ -p 3100:80 \ --env ERIGON_URL="http://localhost:8545" \ --env BEACON_API_URL="http://localhost:5052" \ otterscan/otterscan:develop
- Point your browser to http://localhost:3100
Ephemery testnet
Ephemery testnet is an ephemeral testnet which is reset every ~1 month.
Please see their docs if you want to run Erigon on it.
They also run a public Otterscan instance.
Getting in touch
Otterscan Discord server
Our Discord community server: https://discord.gg/5xM2q2eqDz
Erigon Discord server
Otterscan also has a community channel under the "ecosystem" section of Erigon's Discord.
💡 You must follow their instructions to get an invite
Twitter/X
Official Twitter account: (@otterscan).
Follow the creator on Twitter for more updates (@wmitsuda).
Acknowledgments
Kudos (in no particular order)
We make use of open-source software and integrate many public data sources, mainly:
To the Geth team whose code Erigon is based on.
To the Erigon team that made it possible for regular humans to run an archive node on a retail laptop. Also, they have been very helpful explaining Erigon's internals which made the Otterscan modifications possible.
To the Test in Prod team that made OP-Erigon. Their effort made it possible to run Otterscan against any Optimism Superchain.
To the mdbx team which created the blazingly fast database that empowers Erigon.
To Trust Wallet who sponsors and makes available their icons under a permissive license.
To the owners of the 4bytes repository that we import and use to translate method selectors to human-friendly strings.
To Sourcify, a public, decentralized source code and metadata verification service.
To Ethers, which is the client library we used to interact with the Erigon node. It is high-level enough to hide most JSON-RPC particularities but flexible enough to allow for easy interaction with custom methods.
License
Otterscan is distributed under the MIT License and redistributes MIT-compatible dependencies.
The Otterscan API is implemented inside Erigon and follows its own license (LPGL-3).
The Otterscan Book (this documentation) is distributed under CC BY 4.0.