Merkora is a cross-chain relayer service that monitors events on multiple Layer 1 blockchains (Ethereum and Solana) and relays messages between them to Twine
Merkora serves as a bridge between different blockchain networks, specifically:
- Ethereum
- Solana
The service listens for events on both chains, processes them, and relays messages using the Twine protocol. It uses a PostgreSQL database for state persistence and provides a JSON-RPC interface for interaction.
Merkora is composed of several components:
- Ethereum Listener - Monitors Ethereum for events
- Solana Listener - Monitors Solana for events
- Relayer - Processes and relays messages between chains
- Consensus Module - Maintains state consistency
- JSON-RPC Server - Provides API access
- Database - PostgreSQL for state persistence
- Rust (latest stable version)
- PostgreSQL database
- Access to configured RPC endpoints for Ethereum and Solana
Setup secret environment variables first
export DATABASE_URL="" # postgres connection string
export PRIVATE_KEY="" # twine private keyThe service is configured through config.yaml:
global:
port: 5555 # JSON-RPC server port
log: info # Log level
db-path: ${DATABASE_URL} # PostgreSQL connection string
dummy-mode: false # Skip proof requirements for testing
twine:
# Twine configuration
l2-messenger-contract: ...
sp1-helios: ...
twine-system-storage-contract: ...
rpc: ... # Twine RPC endpoint
private-key: ${PRIVATE_KEY} # Private key for signing transactions
l1s:
ethereum:
# Ethereum chain configuration
name: ethereum
chain-id: 1
rpc: ... # Ethereum RPC endpoint
confirmations: 32
start-height: 4338156
l1-message-queue: ...
solana:
# Solana chain configuration
name: solana-devnet
chain-id: 900
batch-size: 100
start-from: 1497900
program-id: ...
rpc-url: ... # Solana RPC endpoint
telemetry:
json: false
metrics_addr: "127.0.0.1:9108" # Prometheus metrics endpointEnvironment variables can override some configuration values:
TWINE_CONFIG- Path to config file (default:config.yaml)RUST_LOG- Log level (overridesglobal.log)JSONRPC_LISTEN_ADDR- JSON-RPC server address (overridesglobal.port)TWINE_DUMMY_MODE- Enable dummy mode (overridesglobal.dummy-mode)
To build the project:
cargo build --releaseThe binary will be located at target/release/merkora.
- Ensure PostgreSQL is running and accessible with the credentials in your config
- Make sure your
config.yamlis properly set up with valid RPC endpoints - Run the migrations
cd crates/database
cargo sqlx prepare
sqlx migrate run- Run the service:
cargo run --releaseOr run the compiled binary directly:
./target/release/merkoraOnce started, Merkora will:
- Connect to the configured Ethereum and Solana RPC endpoints
- Begin streaming blocks from the configured start heights
- Process events and relay messages between chains
- Expose a JSON-RPC interface on the configured port (default: 5555)
The service can be stopped gracefully with Ctrl+C.
Merkora exposes the following JSON-RPC methods:
health- Returns "ok" if the service is running properlytwmer_sendProof- Accepts Solana proofs and stores them in the database. Rejects Ethereum proofs with an error.
You can check if the service is healthy by calling the health method:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"health","params":[],"id":1}' \
http://localhost:5555To submit a Solana proof, you can call the twmer_sendProof method with a Solana proof object:
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"method":"twmer_sendProof",
"params":[{
"type": "solana",
"chain_name": "solana-devnet",
"consensus_proof": {
"public_values": "...",
"proof": "...",
"vkey": "..."
}
}],
"id":1
}' \
http://localhost:5555Note: Ethereum proofs are not accepted and will return an error.
For testing and development, Merkora supports a "dummy mode" that skips proof requirements:
- Set
dummy-mode: truein your config.yaml or exportTWINE_DUMMY_MODE=true - Events will be sent to Twine immediately after being marked as
ready_to_send = true - No actual proofs are required or fetched
- Verification height checks are skipped
- Duplicate message execution checks are still performed for safety
This mode is useful for rapid testing without waiting for actual proofs or verification heights.
Merkora exposes Prometheus metrics on the configured address (default: 127.0.0.1:9108).
bin/merkora/- Main binarycrates/- Core components:common/- Shared utilities and configurationconsensus/- Consensus state managementdatabase/- Database operationseth-listener/- Ethereum event listenerevm-account-proof-fetcher/- EVM account proof utilitiesmetrics/- Prometheus metricsrelayer/- Core relaying logicrpc/- JSON-RPC server implementationsol-listener/- Solana event listenertwine-client/- Twine clienttypes/- Shared data types