11 stable releases (3 major)
| 3.1.1 | Sep 25, 2025 |
|---|---|
| 3.0.2 | Jul 8, 2025 |
| 3.0.0 | Jun 30, 2025 |
| 2.1.0 | Jun 28, 2025 |
| 0.1.0 | Jun 7, 2025 |
#6 in #u256
290 downloads per month
Used in typed_sqlx_client
100KB
2K
SLoC
ethereum-mysql
Design Purpose:
ethereum-mysql is a pragmatic Rust library that provides type-safe, ergonomic wrappers for Ethereum types (Address, U256, FixedBytes, Bytes) for seamless integration with SQLx and relational databases (MySQL, PostgreSQL, SQLite). The crate is designed for real-world Web3/data engineering scenarios, focusing on:
- String-based storage: All types are stored as human-readable hex strings (e.g.
0x...) in the database, ensuring maximum compatibility and easy inspection. - Type safety: Compile-time and runtime validation for all Ethereum types, eliminating manual string parsing and validation in business logic.
- API ergonomics: Direct arithmetic, comparison, and conversion with Rust primitives for U256, and compile-time address macros for zero-cost, safe usage.
- No binary mode: Binary column support is intentionally omitted; for binary storage, use the official alloy types directly or wait for native support in your stack.
- Minimal, focused features: Only the most practical and widely-used Ethereum types and operations are supported, with optional serde integration.
Features
- Multi-database support: MySQL, PostgreSQL, SQLite via SQLx
- Zero-cost abstractions: Wraps
alloy::primitivestypes (Address,U256,FixedBytes,Bytes) - Type-safe wrappers:
SqlAddress,SqlU256,SqlFixedBytes,SqlBytesfor direct DB integration - Arithmetic operations: Full arithmetic and comparison for
SqlU256(U256), including with Rust primitives - Type conversions: Seamless conversion between wrappers and Rust integer types
- Compile-time macros: Create addresses and hashes at compile time with
sqladdress!,sqlhash! - Constants: Pre-defined constants like
SqlAddress::ZERO,SqlU256::ZERO,SqlU256::ETHER - Decimal utilities: Parse and format Ethereum amounts with
parse_sether/format_sether - Serde support: Optional JSON serialization with serde
- SQLx native: Implements
sqlx_core::Type,sqlx_core::Encode, andsqlx_core::Decodefor all wrappers - Pure Rust: No C dependencies, async-first, production ready
- Common 32-byte types
SqlHashandSqlTopicHashare exported as type aliases forSqlFixedBytes<32>
Database Column Types
All types are stored as strings (hex with 0x prefix) for maximum compatibility:
| Type | Recommended Column Type |
|---|---|
| SqlAddress | VARCHAR(42) |
| SqlU256 | VARCHAR(66) |
| SqlFixedBytes | VARCHAR(2+2*N) |
| SqlBytes | TEXT |
- For PostgreSQL, use
TEXTfor all string types. - For MySQL/SQLite, use
VARCHARas above.
U256 String Encoding
- All U256/FixedBytes types are written as lowercase hex strings with
0xprefix (e.g.0x1234...). - Reading supports both
0x-prefixed hex and decimal strings (but hex is recommended for consistency). - For predictable sorting/comparison, always store as hex.
Key Advantages
🛡️ Type Safety & Validation
All wrappers provide compile-time and runtime validation. No more manual string parsing or error-prone conversions in your business logic.
⚡ Zero Conversion Overhead
Directly bind and retrieve types from SQLx queries—no intermediate conversions or manual parsing required.
🔥 Intuitive Arithmetic
Direct arithmetic and comparison between SqlU256 and Rust primitives, e.g. balance * 25 / 10000.
🚀 API-Ready
Request structs can use SqlAddress/SqlU256 directly for automatic validation and type safety in web APIs.
Quick Start
Add to your Cargo.toml:
ethereum-mysql = "3.1.1"
Example Usage
Address Creation
use ethereum_mysql::{SqlAddress, sqladdress};
use std::str::FromStr;
let zero = SqlAddress::ZERO;
let addr = sqladdress!("0x742d35Cc6635C0532925a3b8D42cC72b5c2A9A1d");
let addr2 = SqlAddress::from_str("0x742d35Cc6635C0532925a3b8D42cC72b5c2A9A1d").unwrap();
const ADMIN: SqlAddress = sqladdress!("0x742d35Cc6635C0532925a3b8D42cC72b5c2A9A1d");
U256 Usage & Ethereum Constants
use ethereum_mysql::{SqlU256, utils::{parse_sether, format_sether}};
use std::str::FromStr;
// Basic usage
let small = SqlU256::from(42u64);
let large = SqlU256::from(u128::MAX);
let zero = SqlU256::ZERO;
let from_decimal = SqlU256::from_str("123456789").unwrap();
let from_hex = SqlU256::from_str("0x75bcd15").unwrap();
assert_eq!(from_decimal, from_hex);
// Ethereum amount calculations
let one_ether = SqlU256::ETHER; // 10^18 wei
let half_ether = SqlU256::ETHER / 2;
let gas_price = SqlU256::from(20_000_000_000u64); // 20 gwei
// Decimal string parsing and formatting
let amount = parse_sether("1.5").unwrap(); // Parse 1.5 ETH
assert_eq!(format_sether(amount).unwrap(), "1.500000000000000000");
// Arithmetic operations
let a = SqlU256::from(100u64);
let b = SqlU256::from(50u64);
let sum = a + b;
let product = a * b;
let doubled = a * 2;
let tripled = 3 * a;
Hash and FixedBytes Creation
use ethereum_mysql::{sqlhash, SqlFixedBytes};
// Create various sized hashes at compile time
const TX_HASH: SqlFixedBytes<32> = sqlhash!(32, "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef");
const FUNCTION_SELECTOR: SqlFixedBytes<4> = sqlhash!(4, "0xa9059cbb");
const TOPIC: SqlFixedBytes<32> = sqlhash!(32, "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef");
SQLx Integration (String Mode)
use ethereum_mysql::{SqlAddress, SqlU256, SqlHash};
use sqlx::MySqlPool;
use std::str::FromStr;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPool::connect("mysql://user:pass@localhost/db").await?;
let user_address = SqlAddress::from_str("0x742d35Cc6635C0532925a3b8D42cC72b5c2A9A1d").unwrap();
let balance = SqlU256::from_str("1000000000000000000").unwrap();
let tx_hash = SqlHash::from_str("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").unwrap();
sqlx::query(
"CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
wallet_address VARCHAR(42) NOT NULL,
balance VARCHAR(66),
tx_hash VARCHAR(66),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)",
)
.execute(&pool)
.await?;
sqlx::query("INSERT INTO users (wallet_address, balance, tx_hash) VALUES (?, ?, ?)")
.bind(&user_address)
.bind(&balance)
.bind(&tx_hash)
.execute(&pool)
.await?;
Ok(())
}
JSON Serialization (with serde)
use ethereum_mysql::{SqlAddress, SqlU256, sqladdress};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct User {
id: u64,
wallet: SqlAddress,
balance: SqlU256,
staked_amount: Option<SqlU256>,
}
let user = User {
id: 1,
wallet: sqladdress!("0x742d35Cc6635C0532925a3b8D42cC72b5c2A9A1d"),
balance: SqlU256::from_str("1500000000000000000").unwrap(),
staked_amount: Some(SqlU256::from_str("1000000000000000000").unwrap()),
};
let json = serde_json::to_string(&user)?;
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Dependencies
~4.5–9MB
~169K SLoC