Cross-chain state sync for Rust — transport-agnostic, divergence-explicit, bot-first.
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.
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.
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 | 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 | 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 |
PRs are welcome. Before submitting, run:
cargo clippy --workspace -- -D warnings
cargo fmt
cargo test --workspaceAll 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.
Licensed under either of MIT or Apache-2.0 at your option.