MP
⚡ Custom Dashboards with Real-Time Data

⛓️ evmify

EVM-ify any chain. One Rust API for EVM and non-EVM blockchains, always answered in EVM format.

CI statuscrates.io versiondocs.rsdownloads

Every blockchain speaks its own RPC dialect. Solana has slots and signatures, Bitcoin has UTXOs and txids, and EVM chains have blocks, receipts and logs. If you build indexers, wallets, analytics or payment flows across chains, you end up writing the same glue code again and again.

evmify is an open-source Rust crate that gives you one interface for all of them: a SOL or BTC transfer comes back as a normal EVM transaction with ERC-20 style Transfer logs, so the code you already have for Ethereum keeps working.

RustBlockchainEVMEthereumSolanaBitcoinRoninJSON-RPCOpen Source
evmify: Solana, Bitcoin and EVM chains go through one adapter → normalizer → transformer pipeline and come out as EVM JSON

📦 Get it

cargo add evmify

Crates.io: crates.io/crates/evmify

Documentation: docs.rs/evmify

Examples: EXAMPLES.md · Roadmap: FUTURE.md

🚀 Features

  • 🔗 One ChainProvider trait for Ethereum, Base, Arbitrum, Ronin, Polygon, Solana, Bitcoin…
  • 🧩 Modular adapter → normalizer → transformer pipeline: add a chain in one file
  • ⚡ Chain shorthands: EvmClient::connect("ronin"), with built-in public RPCs and EVMIFY_RPC_* overrides
  • 🛡️ Verifies the node's chain id, so a misconfigured RPC fails early
  • 🔍 Log scanning over long ranges: newest-first, limits, rate limiting and automatic window halving
  • 🕰️ Exact block for any date via binary search on block timestamps
  • 🔁 Polite HTTP: shared request budget, retries with backoff on HTTP 429
  • 🧾 Unknown fields are kept, never dropped (Base deposits, Arbitrum system txs, Solana v1 transactions)

🦀 Example: several chains, one shape

use evmify::{BlockId, ChainProvider, EvmClient, adapters::solana};

let chains: Vec<Box<dyn ChainProvider>> = vec![
    Box::new(EvmClient::connect("ethereum").await?),
    Box::new(EvmClient::connect("ronin").await?),
    Box::new(solana::connect("solana")?),
];

for chain in &chains {
    let block = chain.block(BlockId::Latest, true).await?.unwrap();
    // Same struct, same JSON, whichever chain it came from.
    println!("{} #{}", chain.chain().name, block.number);
}

💻 Example: inspect any address

Balance, nonce and the latest token and NFT transfers of an address, newest first, on any EVM chain:

cargo run --example address_info -- ronin 0xYourAddress --transfers --since 7d
chain     Ronin (chain id 2020)
balance   123.47 RON
sent      293 transactions

transfers in blocks 62233607..=62276806 (newest first): 2
  2026-10-14 22:36 UTC  block 62274301   OUT   1640 PIXEL   to   0xf05E…a2a7
  2026-10-14 22:34 UTC  block 62274238   IN    1564.76 PIXEL from 0xb32e…AFA3

🎯 Built for

  • Multi-chain backends that want one data model instead of one integration per chain
  • Crypto payments: watch incoming transfers to an address across chains, in one format
  • Indexers and analytics that already understand EVM blocks, receipts and logs
  • Wallets and dashboards showing activity from EVM and non-EVM chains side by side

🤝 Need a chain adapter or a blockchain integration?

I build and maintain evmify. If you need a specific chain supported quickly, an indexer, payment monitoring, or a Rust/Node.js backend around it, I take on freelance work.

Made with 💛 by Mads Paaskesen · Powered by Rust & Open Source · MIT / Apache-2.0
Theme