OP Scan is a transaction explorer tailored specifically for the OP Stack and the Superchain vision. It's focused on being lightweight so that anyone can run it locally next to an OP Stack devnet or any other compatible OP Stack based rollup.
- Lightweight: The code and dependencies are designed to be minimalistic. This ensures minimal resource consumption, allowing anyone to run it locally alongside an OP Stack node when working on a rollup.
- OP Stack Native: This explorer is purpose-built for the OP Stack. It ensures 100% compatibility with rollups in Optimism’s Superchain.
- Scalable: Despite its lightweight design, the explorer is built to handle any scale.
- Open Source: All code is open source from day one. This alignment with the community allows anyone to contribute or fork the repository to meet their specific needs.
OP Scan is built for rollups built on the OP Stack. If you are interested in it, have feedback or feature request, submit an issue here.
Here's a video walkthrough on how to launch the explorer locally configured for OP Sepolia testnet.
The app requires the following dependencies:
Node.js >= 22
pnpm >= 9
Clone this repository:
git clone https://github.com/walnuthq/op-scan.git
Install the dependencies:
pnpm install
Copy .env.local.example
into .env.local
at the root of your repository and populate it with your own values.
In particular, configure both L1 and L2 chains:
NEXT_PUBLIC_L1_CHAIN_ID="11155111"
NEXT_PUBLIC_L1_NAME="Sepolia"
NEXT_PUBLIC_L1_RPC_URL="https://ethereum-sepolia-rpc.publicnode.com"
L1_RPC_WS="wss://ethereum-sepolia-rpc.publicnode.com"
NEXT_PUBLIC_L2_CHAIN_ID="11155420"
NEXT_PUBLIC_L2_NAME="OP Sepolia"
NEXT_PUBLIC_L2_RPC_URL="https://optimism-sepolia-rpc.publicnode.com"
L2_RPC_WS="wss://optimism-sepolia-rpc.publicnode.com"
You can get free node rpcs url by signing up to services such as Alchemy, Infura or QuickNode.
For devnet usage, follow this tutorial to run a local development environment that will spawn both L1 and L2 chains.
Once your OP Stack devnet is ready, copy your L1 (el-1-geth-lighthouse
) and L2 (op-el-1-op-geth-op-node-rollup-1
) RPC urls and get the corresponding chain ids using Foundry's cast:
cast chain-id --rpc-url http://127.0.0.1:32771
cast chain-id --rpc-url http://127.0.0.1:32780
This will give you the following local chain config:
NEXT_PUBLIC_L1_CHAIN_ID="3151908"
NEXT_PUBLIC_L1_NAME="Goerli"
NEXT_PUBLIC_L1_RPC_URL="http://127.0.0.1:32771"
L1_RPC_WS="ws://127.0.0.1:32772"
NEXT_PUBLIC_L2_CHAIN_ID="12345"
NEXT_PUBLIC_L2_NAME="rollup-1"
NEXT_PUBLIC_L2_RPC_URL="http://127.0.0.1:32780"
L2_RPC_WS="ws://127.0.0.1:32781"
Next you will need to find the L1 contract addresses for both the Optimism Portal and the Cross Domain Messenger. You will find the L1CrossDomainMessenger address in your local devnet logs:
- L1CrossDomainMessengerProxy: 0x170d06930Ce8c7487EF12Be36d20C400Eb0fA8B2
Then fetch the Portal address from the Cross Domain Messenger using cast call
:
cast call 0x170d06930Ce8c7487EF12Be36d20C400Eb0fA8B2 "PORTAL()" --rpc-url http://127.0.0.1:32771
The result being an address, only take the first 20 bytes from the returned value:
0x000000000000000000000000e373471c58424978b4652db046817c209f09e645 -> 0xe373471c58424978b4652db046817c209f09e645
Copy these addresses to your local chain config:
NEXT_PUBLIC_L1_CROSS_DOMAIN_MESSENGER_ADDRESS="0x170d06930Ce8c7487EF12Be36d20C400Eb0fA8B2"
NEXT_PUBLIC_OPTIMISM_PORTAL_ADDRESS="0xe373471c58424978b4652db046817c209f09e645"
If you don't want to run the explorer with your local chain setup, you will find all the necessary environment variables in .env.local.example
to configure the explorer with OP Sepolia or OP Mainnet.
If you want to be able to use the Write Contract feature on verified contracts, you will also need to provide a Reown project ID.
NEXT_PUBLIC_REOWN_PROJECT_ID="REOWN_PROJECT_ID"
To run the indexer, first set up your DATABASE_URL
in .env.local
(we use SQLite by default, but you can switch to PostgreSQL by changing the Prisma provider in prisma/schema.prisma
) and configure websocket connections to your L1/L2 chains:
DATABASE_URL="file:dev.db"
L1_RPC_WS="wss://ethereum-sepolia-rpc.publicnode.com"
L2_RPC_WS="wss://optimism-sepolia-rpc.publicnode.com"
Then you can sync your local database with the Prisma schema:
pnpm prisma:db:push
Now you will be able to start indexing the blockchain by running the op-indexer
command:
pnpm op-indexer
You should start seeing blocks getting indexed in your terminal, and you can explore the state of your local database using Prisma studio:
pnpm prisma:studio
If you need to change the Prisma schema at some point, make sure to regenerate the Prisma client and push to your local database:
pnpm prisma:generate
pnpm prisma:db:push
Indexing a blockchain puts a heavy load on the RPC endpoint, as you need to perform many JSON-RPC requests to fully index a block (along with transactions and logs). When indexing non-local chains you will probably encounter 429 errors related to rate-limiting, you may provide up to 5 fallback RPC URLs in case this happens:
NEXT_PUBLIC_L1_FALLBACK1_RPC_URL="https://rpc.ankr.com/eth_sepolia"
NEXT_PUBLIC_L2_FALLBACK1_RPC_URL="https://rpc.ankr.com/optimism_sepolia"
NEXT_PUBLIC_L1_FALLBACK2_RPC_URL="https://endpoints.omniatech.io/v1/eth/sepolia/public"
NEXT_PUBLIC_L2_FALLBACK2_RPC_URL="https://endpoints.omniatech.io/v1/op/sepolia/public"
NEXT_PUBLIC_L1_FALLBACK3_RPC_URL="https://sepolia.drpc.org"
NEXT_PUBLIC_L2_FALLBACK3_RPC_URL="https://optimism-sepolia.drpc.org"
NEXT_PUBLIC_L1_FALLBACK4_RPC_URL="https://eth-sepolia.g.alchemy.com/v2/FALLBACK4_API_KEY"
NEXT_PUBLIC_L2_FALLBACK4_RPC_URL="https://opt-sepolia.g.alchemy.com/v2/FALLBACK4_API_KEY"
NEXT_PUBLIC_L1_FALLBACK5_RPC_URL="https://sepolia.infura.io/v3/FALLBACK5_API_KEY"
NEXT_PUBLIC_L2_FALLBACK5_RPC_URL="https://optimism-sepolia.infura.io/v3/FALLBACK5_API_KEY"
You can pass several parameters to the indexer to control the indexing range and execution:
--l2-from-block
(short-f
, defaults to latest block) start indexing from this L2 block.--l2-index-block
(short-b
) index this particular L2 block number.--l1-from-block
(defaults to latest block) start indexing from this L1 block.--l1-index-block
index this particular L1 block number.--index-delay
(short-d
, defaults to 1000) delay in ms between indexing 2 blocks to avoid overloading the RPC.
Example of running the indexer:
pnpm op-indexer -f 123416717 --l1-index-block 20426733 --l1-index-block 20426726 -d 500
When you're done configuring your environment variables, you can build the app:
pnpm build
Make sure the indexer is running, then launch the explorer to see it live at http://localhost:3000
pnpm start
Alternatively, you can launch the explorer in dev mode if you want to customize it:
pnpm dev
Head on to the issues tab to find a list of open contributions. Before making your first contribution, get familiar with our contributor guidelines.