Spin up your proposer
After you have spun up your sequencer, you need to attach a proposer to post your L2 state roots data back onto L1 so we can prove withdrawal validity. The proposer is a critical component that enables trustless L2-to-L1 messaging and creates the authoritative view of L2 state from L1's perspective.
This guide assumes you already have a functioning sequencer and the necessary L1 contracts deployed using op-deployer
. If you haven't set up your sequencer yet, please refer to the [sequencer guide](Todo - Add this link when it's live) first.
Understanding the proposer's role
The proposer (op-proposer
) serves as a crucial bridge between your L2 chain and L1. Its primary responsibilities include:
- State commitment: Proposing L2 state roots to L1 at regular intervals
- Withdrawal enablement: Providing the necessary commitments for users to prove and finalize withdrawals
The proposer creates dispute games via the DisputeGameFactory
contract, enabling permissionless challenging of proposed state roots.
Prerequisites
Before setting up your proposer, ensure you have:
Running infrastructure:
- A synced and operational sequencer node
- Access to a L1 RPC endpoint
- The rollup node (
op-node
) running and accessible
From op-deployer deployment:
- Successfully deployed L1 contracts using
op-deployer apply
- Access to your deployment output (
genesis
androllup
) files.
Security setup:
- A dedicated proposer private key
Network information:
- Your L2 chain ID and network configuration
- L1 network details (chain ID, RPC endpoints)
Software installation
Build from source
Clone and build op-proposer
# If you don't already have the optimism repository from the sequencer setup
git clone https://github.com/ethereum-optimism/optimism.git
cd optimism
# Checkout the latest release tag
git checkout op-proposer/v1.10.0
# Build op-proposer
cd op-proposer
make op-proposer
# Binary will be available at ./bin/op-proposer
Verify installation
./bin/op-proposer --version
Configuration setup
1. Organize your workspace
Create your proposer working directory:
# Create proposer directory at the same level as your sequencer
mkdir proposer-node
cd proposer-node
# Create scripts directory
mkdir scripts
2. Extract contract addresses
Extract the necessary contract addresses from your op-deployer output:
# Extract L1 contract addresses from your op-deployer deployment
cd proposer-node
# Copy the L1 contracts file from op-deployer, update to paths to wherever your `.deployer/state.json` live
cp ../.deployer/state.json .
# Extract the DisputeGameFactory address
GAME_FACTORY_ADDRESS=$(cat state.json | jq -r '.opChainDeployments[0].disputeGameFactoryProxyAddress')
echo "DisputeGameFactory Address: $GAME_FACTORY_ADDRESS"
3. Set up environment variables
Create your .env
file with the actual values:
# Create .env file with your actual values
# L1 Configuration - Replace with your actual RPC URL
L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_ACTUAL_INFURA_KEY
# L2 Configuration - Should match your sequencer setup
L2_RPC_URL=http://localhost:8545
ROLLUP_RPC_URL=http://localhost:8547
# Contract addresses - Extract from your op-deployer output
GAME_FACTORY_ADDRESS=YOUR_ACTUAL_GAME_FACTORY_ADDRESS
# Private key - Replace with your actual proposer private key
PROPOSER_PRIVATE_KEY=0xYOUR_ACTUAL_PROPOSER_PRIVATE_KEY
# Proposer configuration
PROPOSAL_INTERVAL=3600s
GAME_TYPE=0
POLL_INTERVAL=20s
# RPC configuration
PROPOSER_RPC_PORT=8560
Important: Replace ALL placeholder values (YOUR_ACTUAL_*
) with your real configuration values!
4. Get your proposer private key
Extract the proposer private key from your op-deployer intent file:
# View your intent file to find the proposer private key
cat ~/.deployer/intent.toml
# Look for a section like:
# [chains.my-chain.roles.proposer]
# privateKey = "0x..."
Proposer configuration
Create scripts/start-proposer.sh
:
#!/bin/bash
source .env
# Path to the op-proposer binary we built
../optimism/op-proposer/bin/op-proposer \
--poll-interval=$POLL_INTERVAL \
--rpc.port=$PROPOSER_RPC_PORT \
--rpc.enable-admin \
--rollup-rpc=$ROLLUP_RPC_URL \
--l1-eth-rpc=$L1_RPC_URL \
--private-key=$PROPOSER_PRIVATE_KEY \
--game-factory-address=$GAME_FACTORY_ADDRESS \
--game-type=$GAME_TYPE \
--proposal-interval=$PROPOSAL_INTERVAL \
--num-confirmations=1 \
--resubmission-timeout=30s \
--wait-node-sync=true \
--log.level=info
Starting the proposer
1. Verify prerequisites
Ensure your sequencer and op-node are running:
# Test L1 connectivity
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
$L1_RPC_URL
# Test L2 connectivity
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
$L2_RPC_URL
# Test rollup node connectivity
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"optimism_syncStatus","params":[],"id":1}' \
$ROLLUP_RPC_URL
2. Start the proposer
# Make the script executable
chmod +x scripts/start-proposer.sh
# Start the proposer
./scripts/start-proposer.sh
Verification
Verify your proposer is working correctly:
Check proposer status
# Verify proposer is responsive
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"optimism_version","params":[],"id":1}' \
http://localhost:8560
Monitor dispute games on L1
# Check latest dispute game count (requires cast from foundry)
cast call $GAME_FACTORY_ADDRESS "gameCount()" --rpc-url $L1_RPC_URL
Monitor your proposer's ETH balance and gas usage to ensure continuous operation. Your proposer is now operational!
Next steps
- For detailed parameter documentation, see the proposer configuration reference.
- For more detail on deploying new dispute games with OPCM, see the docs.
- checkout the migrating to permissionless fault proofs guide
- For cost optimization resources, check out the Fee calculation tools.