Skip to content

arpjw/xenith

Repository files navigation

xenith

Cross-chain state sync for Rust — transport-agnostic, divergence-explicit, bot-first.

xenith-core xenith-layerzero xenith-sync xenith-read docs.rs License

The Problem

Multi-chain protocols share state across EVM networks using ad-hoc messaging (LayerZero, CCIP, Axelar), but there is no standardized primitive that sits above those transports. Every team ends up rewriting the same glue: serializing state updates into message payloads, tracking in-flight message IDs, comparing observed values across chains, and deciding what to do when two chains disagree. The absence of a shared abstraction means teams are locked into a single messaging protocol from day one, and divergence bugs — where different chains hold silently inconsistent state — are caught only when a liquidation misfires or an arbitrage reverts.

What xenith is

xenith is a transport-agnostic, Rust-native library that treats cross-chain state sync as a first-class primitive. You plug in any messaging transport (LayerZero, CCIP, or your own), and xenith handles local persistence, message dispatch, and read-back under a ReadStrategy you choose. Diverged state is never silently resolved — SyncStatus::Diverged surfaces to the caller who is always in control of conflict resolution. The MultiChainReader issues parallel RPC reads across chains so keeper bots and arbitrage engines get consistent snapshots without blocking on sequential calls.

Quick Start

Add the crates you need to Cargo.toml:

[dependencies]
xenith-core      = "0.1"
xenith-layerzero = "0.1"
xenith-sync      = "0.1"

Push a state value from Ethereum to Arbitrum, then read it back:

use std::sync::Arc;
use bytes::Bytes;
use xenith_core::{ChainId, InMemoryStore, ReadStrategy, StateKey};
use xenith_layerzero::LayerZeroTransport;
use xenith_sync::{SyncConfig, SyncEngine};

#[tokio::main]
async fn main() -> xenith_core::Result<()> {
    // LayerZero endpoint IDs: Ethereum mainnet = 30101, Arbitrum = 30110
    let transport = Arc::new(LayerZeroTransport::new(
        [0u8; 20], // endpoint contract address on the source chain
        vec![
            (ChainId::from(1),     30101),
            (ChainId::from(42161), 30110),
        ],
    ));

    let engine = SyncEngine::new(
        transport,
        Arc::new(InMemoryStore::default()),
        SyncConfig::default(),
    );

    let key = StateKey::new("uniswap", "pool", "0xabc123");

    // Store locally and broadcast to Arbitrum.
    let receipt = engine
        .push(
            key.clone(),
            Bytes::from_static(b"price=3400"),
            vec![ChainId::from(42161)],
            ChainId::from(1), // source chain
            None,             // no on-chain metadata needed for this push
        )
        .await?;

    println!("dispatched to {} chain(s)", receipt.successes.len());

    // Read back; Ethereum is the declared source of truth.
    let state = engine
        .read(key, ReadStrategy::SourceOfTruth(ChainId::from(1)))
        .await?;

    println!("status: {:?}", state.status); // SyncStatus::Synced
    println!("data:   {:?}", state.value.data);

    Ok(())
}

Crate Overview

Crate crates.io docs.rs Description
xenith-core Transport-agnostic traits, domain newtypes, XenithError, InMemoryStore, and ConflictResolver. No external deps beyond alloy-primitives, async-trait, thiserror, and bytes.
xenith-layerzero LayerZero v2 MessagingTransport implementation. Stub behaviour ships by default; real endpoint calls (LayerZeroLiveTransport, K256Signer) are gated behind the live feature.
xenith-sync SyncEngine — the primary API surface. Composes a transport and a store to provide push, subscribe, read, and resolve. Ships InMemoryStore (from core) and JsonFileStore for file-backed persistence.
xenith-read MultiChainReader — issues parallel RPC reads across many chains simultaneously and reports storage-slot divergence. MockProvider always available; AlloyProvider (real JSON-RPC) gated behind live-rpc.

Feature Flags

Crate Flag What it enables
xenith-core testing Exports testing module with compliance-test helpers and the transport_compliance_tests! macro
xenith-layerzero live LayerZeroLiveTransport with real endpoint calls, K256Signer, and encode_executor_lz_receive_option
xenith-read live-rpc AlloyProvider backed by real JSON-RPC nodes via alloy

All feature flags are off by default in their respective crates. Enable only what you need.

Transport Support

Transport Status Notes
LayerZero v2 v0.1 Stub impl ships now; live feature gates real endpoint calls
Chainlink CCIP v0.2 planned xenith-ccip crate
Axelar v0.3 planned xenith-axelar crate

Contributing

PRs are welcome. Before submitting, run:

cargo clippy --workspace -- -D warnings
cargo fmt
cargo test --workspace

All three must pass clean. Clippy warnings are treated as errors; the formatter is non-negotiable. If you are adding a new transport, implement the transport_compliance_tests! macro suite from xenith-core to verify conformance.

Stability: xenith follows Semantic Versioning. While on 0.x.y, minor version bumps may include breaking changes. Patch bumps are always backwards compatible. Subscribe to releases on GitHub to be notified of breaking changes.

Published crates: All four crates (xenith-core, xenith-layerzero, xenith-sync, xenith-read) are available on crates.io and documented on docs.rs. New versions are published manually by the maintainer after each release tag.

License

Licensed under either of MIT or Apache-2.0 at your option.

About

A Rust library for transport-agnostic cross-chain state sync

Topics

Resources

License

Unknown, MIT licenses found

Licenses found

Unknown
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages