Skip to content

twinexyz/merkora

Repository files navigation

Merkora

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

Overview

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.

Architecture

Merkora is composed of several components:

  1. Ethereum Listener - Monitors Ethereum for events
  2. Solana Listener - Monitors Solana for events
  3. Relayer - Processes and relays messages between chains
  4. Consensus Module - Maintains state consistency
  5. JSON-RPC Server - Provides API access
  6. Database - PostgreSQL for state persistence

Prerequisites

  • Rust (latest stable version)
  • PostgreSQL database
  • Access to configured RPC endpoints for Ethereum and Solana

Configuration

Setup secret environment variables first

export DATABASE_URL=""          # postgres connection string
export PRIVATE_KEY=""           # twine private key

The 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 endpoint

Environment variables can override some configuration values:

  • TWINE_CONFIG - Path to config file (default: config.yaml)
  • RUST_LOG - Log level (overrides global.log)
  • JSONRPC_LISTEN_ADDR - JSON-RPC server address (overrides global.port)
  • TWINE_DUMMY_MODE - Enable dummy mode (overrides global.dummy-mode)

Building

To build the project:

cargo build --release

The binary will be located at target/release/merkora.

Running

  1. Ensure PostgreSQL is running and accessible with the credentials in your config
  2. Make sure your config.yaml is properly set up with valid RPC endpoints
  3. Run the migrations
cd crates/database
cargo sqlx prepare
sqlx migrate run
  1. Run the service:
cargo run --release

Or run the compiled binary directly:

./target/release/merkora

Usage

Once started, Merkora will:

  1. Connect to the configured Ethereum and Solana RPC endpoints
  2. Begin streaming blocks from the configured start heights
  3. Process events and relay messages between chains
  4. Expose a JSON-RPC interface on the configured port (default: 5555)

The service can be stopped gracefully with Ctrl+C.

RPC Methods

Merkora exposes the following JSON-RPC methods:

  • health - Returns "ok" if the service is running properly
  • twmer_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:5555

To 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:5555

Note: Ethereum proofs are not accepted and will return an error.

Dummy Mode

For testing and development, Merkora supports a "dummy mode" that skips proof requirements:

  1. Set dummy-mode: true in your config.yaml or export TWINE_DUMMY_MODE=true
  2. Events will be sent to Twine immediately after being marked as ready_to_send = true
  3. No actual proofs are required or fetched
  4. Verification height checks are skipped
  5. Duplicate message execution checks are still performed for safety

This mode is useful for rapid testing without waiting for actual proofs or verification heights.

Monitoring

Merkora exposes Prometheus metrics on the configured address (default: 127.0.0.1:9108).

Project Structure

  • bin/merkora/ - Main binary
  • crates/ - Core components:
    • common/ - Shared utilities and configuration
    • consensus/ - Consensus state management
    • database/ - Database operations
    • eth-listener/ - Ethereum event listener
    • evm-account-proof-fetcher/ - EVM account proof utilities
    • metrics/ - Prometheus metrics
    • relayer/ - Core relaying logic
    • rpc/ - JSON-RPC server implementation
    • sol-listener/ - Solana event listener
    • twine-client/ - Twine client
    • types/ - Shared data types

About

Merkora

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors