🥷 Try it live — no local setup. ICP Ninja is a web-based IDE that builds and deploys this project to the mainnet for free, right in your browser. Click the badge above, or hit Deploy if you're already in Ninja. To build and run it locally instead, follow the steps below.
The EVM Block Explorer example demonstrates how an ICP canister can fetch block data directly from Ethereum and other EVM-compatible chains. Using HTTPS outcalls via the EVM RPC canister, canisters on ICP can read on-chain data without a bridge or oracle. The same pattern applies to any EVM-compatible chain supported by the EVM RPC canister.
- Node.js v18+
- icp-cli:
npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm - Rust with
wasm32-unknown-unknowntarget:rustup target add wasm32-unknown-unknown
Clone the example project:
git clone https://github.com/dfinity/examples
cd examples/rust/evm_block_explorerStart the local network, deploy all canisters (including the local EVM RPC canister), and run the tests:
icp network start -d
icp deploy
bash test.sh
icp network stopTo start a frontend dev server with hot reload during frontend development:
npm run dev --prefix frontendOn mainnet, the evm_rpc canister is already deployed at 7hfb6-caaaa-aaaar-qadga-cai. Deploy only the backend and frontend — icp-cli injects the correct canister ID via the ic environment configuration in icp.yaml:
icp deploy -e icThe backend/backend.did file defines the backend canister's public interface. The frontend TypeScript bindings are auto-generated from this file during the frontend build.
If you modify the backend's public API, rebuild the canister and regenerate the .did file:
icp build backend && candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.didThe example uses PublicNode by default — a free, no-registration provider that works out of the box locally and on mainnet. This is sufficient for getting started and automated testing.
For production deployments requiring premium providers (Alchemy, Ankr, BlockPi), refer to the EVM RPC canister documentation for how to configure API keys. Once configured, change RpcServices::EthMainnet(Some(vec![EthMainnetService::PublicNode])) in backend/src/lib.rs to RpcServices::EthMainnet(None) to use all configured providers for better consensus.
If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the security best practices for developing on ICP. This example may not implement all the best practices.