- 🔗 Cross-Chain Communication: Securely relay Ethereum block hashes to Starknet
- 🔒 ZK-Powered Verification: Use zero-knowledge proofs for efficient verification
- 📊 Fee State Proofs: Generate and verify cryptographic proofs of Ethereum gas fees
- 🚀 Scalable Architecture: Process Ethereum blocks in batches with MMR accumulation
- 🛠️ Flexible Deployment: Run via Docker or compile manually for development
Fossil is a trustless data infrastructure designed to store Ethereum Layer 1 (L1) base gas fee data on Starknet, enabling verified off-chain computation for the Pitchlake options market. It leverages the RISC0 zkVM to perform deterministic data extraction, validation, and aggregation, producing zero-knowledge proofs verifiable on-chain.
Data Ingestion and Validation:
- Fossil retrieves finalized Ethereum block headers from the Fossil Postures Database, which is populated by an indexer tracking all finalized Ethereum blocks
- Block headers are processed in batches of 1024 inside the RISC0 VM to ensure trustlessness
- Within the VM, each block header is rehashed to confirm its computed hash matches the block hash
- Parent-child relations between headers are validated to ensure sequential integrity
- Once verified, the base fee per gas is extracted from each header
- Hourly average base fees are computed across the verified blocks
Data Storage:
- A Merkle Mountain Range (MMR) is constructed using the block hashes as leaves
- The prover commits to the proof journal: hourly average base fees, MMR root hash, and total number of MMR leaves
- The full MMR state is exported to a SQLite database, uploaded to IPFS, and referenced by its CID
- Only the proof journal and IPFS CID are stored on-chain in the Fossil Store contract
System Processes:
-
MMR Builder (Backward Reconstruction)
- Reconstructs historical Ethereum data backward from a known finalized block
- Starting from the latest finalized block hash and number, iteratively builds MMR batches backward until the genesis block
-
Light Client (Forward Synchronization)
- Continuously updates Fossil's data forward as new finalized blocks are produced
- Works alongside an off-chain relayer that sends finalized block numbers and hashes from Ethereum L1 to Starknet L2 every 6 hours (configurable) through L1 → L2 messaging contracts
- On Starknet, the L1MessageProxy contract receives and forwards block data to Fossil Store, emitting an update event
- The light client retrieves the latest batch metadata, updates the MMR from the last known block to the new finalized block
- If a batch is incomplete, reconstructs state using on-chain MMR data and the corresponding IPFS snapshot before continuing
Pitchlake Integration:
- The Pitchlake Coprocessor (separate repository) leverages Fossil's validated fee data for on-chain computations
- Requests are processed through a proving service that executes computations in RISC0 VM and generates ZK proofs
- Verified proofs are submitted to Starknet, and journal data is extracted and transmitted to the Pitchlake Vault contract
FOR FUTURE DEVELOPERS: Review these critical considerations before continuing development.
Fossil currently relies on Bonsai (RISC0's managed proving service), which is planned for deprecation. RISC0 recommends migrating to Boundless, a decentralized proving marketplace.
Key Implications:
- Migration requires modifications to proof submission and verification workflows
- Proof batching, latency, and cost structures will change
- Security guarantees remain equivalent but need protocol-level coordination
Given Pitchlake's computational complexity and Fossil's dataset size, RISC0 may not be the most efficient long-term solution.
Recommendations:
- Boundless Migration - If maintaining RISC0 compatibility is priority
- Evaluate SP1 (Succinct) - Offers lower latency and better scalability for large computations
- Requires proof format and verification contract updates
- Could significantly reduce compute costs
Action Required: Future teams should benchmark alternative provers (Boundless, SP1, etc.) and plan migration strategy based on performance, cost, and timeline constraints.
📖 See Technical Specification - Section 9 for detailed analysis and migration guidance.
For comprehensive technical documentation, architecture details, and system specifications, see the Documentation Index.
This README outlines two deployment approaches:
- 🐋 Docker-Based Deployment: Recommended for most users, handles all dependencies automatically
- 🔧 Manual Compilation: For development and debugging, runs light client binaries from source
-
Install Docker Desktop (includes Docker Engine and Compose)
-
For Linux only: Install Docker Buildx
mkdir -p ~/.docker/cli-plugins/ curl -L https://github.com/docker/buildx/releases/download/v0.12.1/buildx-v0.12.1.linux-amd64 -o ~/.docker/cli-plugins/docker-buildx chmod +x ~/.docker/cli-plugins/docker-buildx
This approach builds a local Ethereum and Starknet network for development and testing:
-
Set up configuration:
cp config/.env.example .env cp config/.env.docker.example .env.docker
-
Start core network infrastructure:
docker-compose up -d docker-compose logs -f # Monitor until initialization complete -
Run MMR accumulation:
# Run with default settings (build all batches until block #0) ENV_FILE=.env.docker docker-compose -f docker-compose.accumulation.yml up # Or specify number of batches (build with 4 batches only) ENV_FILE=.env.docker NUM_BATCHES=4 docker-compose -f docker-compose.accumulation.yml up
-
Run The Light Client:
# Run with default settings ENV_FILE=.env.docker docker-compose -f docker-compose.client.yml up -
Run The Relayer:
# Run with default settings (default: relays block hashes every 60 minutes) ENV_FILE=.env.docker docker-compose -f docker-compose.relayer.yml up # Or specify the relay time (relays block hashes every 5 minutes) ENV_FILE=.env.docker RELAY_TIME_MINUTES=5 docker-compose -f docker-compose.relayer.yml up
This approach connects to existing Ethereum and Starknet networks:
-
Set up configuration:
# For testnet (Sepolia) cp config/.env.local.example .env.sepolia # For mainnet cp config/.env.local.example .env.mainnet
-
Update the configuration file with:
- Ethereum RPC endpoint
- Starknet RPC endpoint
- Contract addresses for deployed contracts
- API keys and other required credentials
-
Run MMR accumulation:
# For testnet (Sepolia) source .env.sepolia docker-compose -f docker-compose.accumulation.yml up # For mainnet source .env.mainnet docker-compose -f docker-compose.accumulation.yml up # Optionally specify number of batches source .env.sepolia NUM_BATCHES=4 docker-compose -f docker-compose.accumulation.yml up
-
Run The Light Client:
# Run with default settings ENV_FILE=.env.sepolia docker-compose -f docker-compose.client.yml up -
Run The Relayer:
# Run with default settings (default: relays block hashes every 60 minutes) ENV_FILE=.env.sepolia docker-compose -f docker-compose.relayer.yml up
The Docker image will be automatically pulled from DockerHub, so no local build is required.
# View containers
docker ps
# View logs
docker-compose logs -f
docker-compose -f docker-compose.accumulation.yml logs -f
# Stop everything
docker-compose down
docker-compose -f docker-compose.accumulation.yml downThis setup uses Docker only for networks (Ethereum & StarkNet) and contract deployments, while running light client components directly with Cargo.
You can install all prerequisites automatically with:
make setupThis will install all necessary dependencies:
- Rust (with nightly toolchain)
- Foundry for Ethereum development
- RISC Zero tools
- Starknet development toolchain (scarb, starknet-foundry, starkli)
- Platform-specific requirements
For individual component installation:
# Install only specific components
make setup-rust # Install Rust and nightly toolchain
make setup-foundry # Install Foundry
make setup-risc0 # Install RISC Zero
make setup-starknet # Install Starknet tools
make setup-platform # Install platform-specific dependencies
make init-repo # Initialize git submodulesSee the Makefile for all available commands.
-
Configure environment:
cp config/.env.local.example .env.local
-
Start networks and deploy contracts:
chmod +x scripts/build-network.sh ./scripts/build-network.sh
Option 1: Standard deployment (with container build)
docker-compose up
Option 2: Faster deployment (build locally first) To save time during network container boot-up, you can build the Starknet contracts locally before running docker-compose:
# Build Starknet contracts locally scarb build cd ../.. # Run docker-compose with NO_BUILD=1 to skip the build step in the container NO_BUILD=1 docker-compose up
Wait for the
deploy-starknetcontainer to complete the deployment of all StarkNet contracts. The deployment is finished when you see a log message indicating environment variables have been updated. (it might take a few minutes) -
Build the project:
cargo build
-
Build MMR and generate proofs:
cargo run --bin build-mmr -- --num-batches 2 --env-file .env.local
-
Start the client:
cargo run --bin client -- --env-file .env.local
-
Start the relayer:
chmod +x scripts/run_relayer_local.sh ./scripts/run_relayer_local.sh
-
Test Fee Proof Fetching:
starkli call <fossil_store_contract_address> get_avg_fees_in_range <start_timestamp> <end_timestamp> --rpc http://localhost:5050
When requesting state proofs for fees, you can query any hour-aligned timestamp or range within the processed blocks. The system aggregates fees hourly and requires timestamps to be multiples of 3600 seconds (1 hour).
For example, if blocks from timestamp 1704067200 (Jan 1, 2024 00:00:00 UTC) to 1704153600 (Jan 2, 2024 00:00:00 UTC) have been processed:
- You can query a single hour: 1704070800 (Jan 1, 2024 01:00:00 UTC)
- Or a range: 1704067200 to 1704153600 (full 24 hours)
- Or any subset of hours within these bounds
Key validation rules:
- All timestamps must be hour-aligned (multiples of 3600 seconds)
- For range queries, start timestamp must be ≤ end timestamp
- Queries return weighted average fees based on number of blocks in each hour
Note: While blocks are processed in batches internally, fee queries operate on hour boundaries regardless of batch structure.
To build the docker containers locally (currently only supported on Linux machines):
chmod +x scripts/build-all.sh
./scripts/build-all.shThis process might take a while depending on your machine. Note that building images locally is currently only supported on Linux due to platform-specific binary compatibility requirements. macOS and Windows users should use the pre-built images from DockerHub instead.
There are multiple contracts that need to be deployed on Ethereum and Starknet:
- L1 Message Sender (Ethereum)
- Fossil Store (Starknet)
- L1 Message Proxy (Starknet)
- Groth16 Verifier (Starknet)
- Fossil Verifier (Starknet)
Make sure you have the following installed:
- Foundry (https://book.getfoundry.sh/getting-started/installation)
- Starkli (https://book.starkli.rs/installation)
You'll need both Ethereum and Starknet wallets for deployment:
-
Create a new
.env.sepoliafile:ETH_RPC_URL= STARKNET_RPC_URL= ACCOUNT_PRIVATE_KEY= STARKNET_ACCOUNT= STARKNET_ACCOUNT_ADDRESS=
-
Set up RPC providers:
ETH_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/xxxxxx # replace with your API key STARKNET_RPC_URL=https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/xxxxxx # replace with your API key
-
Set up Ethereum wallet (Metamask):
-
Download Metamask from https://metamask.io/download
-
Create a wallet and save the seed phrase
-
Get your private key and add it to
.env.sepolia:ACCOUNT_PRIVATE_KEY=0x01234456 # replace with your actual private key
-
-
Set up Starknet wallet (Starkli):
starkli account oz init deploy_wallet starkli account deploy deploy_wallet
Add to
.env.sepolia:STARKNET_ACCOUNT=deploy_wallet # path to your account file STARKNET_ACCOUNT_ADDRESS=0x00ecac1256b0f48686dd90819299537d3bd2a8fc192402b926d3eff516307f87 # your address
-
Add Starknet messaging contract:
SN_MESSAGING=0xE2Bb56ee936fd6433DC0F6e7e3b8365C906AA057
chmod +x ./scripts/deploy-ethereum.sh
./scripts/deploy-ethereum.sh sepoliaThis will update your .env.sepolia with the L1_MESSAGE_SENDER address.
chmod +x ./scripts/deploy-starknet.sh
./scripts/deploy-starknet.sh sepoliaThis will update your .env.sepolia with addresses for:
- L2_MSG_PROXY
- FOSSIL_STORE
- STARKNET_VERIFIER
- FOSSIL_VERIFIER
To deploy to Sepolia testnet:
-
Configure Environment:
cp config/.env.local.example .env.sepolia nano .env.sepolia
Ensure these variables are properly set:
ETH_RPC_URL: Your Sepolia Ethereum RPC endpointACCOUNT_PRIVATE_KEY: Private key for deploymentSN_MESSAGING: Starknet core messaging contract address
-
Reset deployment:
docker-compose down docker-compose -f docker-compose.accumulation.yml down docker network rm fossil-network
-
Remove orphaned containers:
docker-compose up -d --remove-orphans
- Ensure IPFS daemon is running
- Verify Docker network connectivity
- Check logs:
docker-compose logs -f