Alloy: Fast, battle-tested and well-documented building blocks for Ethereum, in Rust
We’re excited to announce alloy-rs/core, a rewrite of the popular ethers-core package and the ethabi crate. Core offers:
- Alloy Primitives: We provide new fundamental types for hashes, fixed-byte arrays, and signed and unsigned integers (built on Remco’s uint library). These types implement common traits sanely (no more truncated hashes like “0x1234…5678”), aim for no_std compatibility, and provide common helper functions for usage in applications.
- Alloy RLP: A canonical RLP implementation.
- Alloy RPC Types: All the RPC types when talking to a chain are available using our newly defined types.
- Syn Solidity: A
syn
-powered Solidtiy parser, specifically designed for Rust procedural macros. It aims to mimic the behavior of the official Solidity compiler (Solc) when it comes to parsing valid Solidity code. This is a powerful abstraction which we leverage for building performant compile-time functionalities, like static ABI coders (see below). - Alloy Solidity Types: A compile-time representation of Ethereum's type system with ABI and EIP-712 support. This allows for clean UX and high encoding/decoding speed without redundant layers of abstraction. This static abi encoder is built on a robust representation of Solidity’s type system in Rust. Users access it via the sol! procedural macro, which parses Solidity snippets to generate native Rust code. The static encoder benches at 2-3x faster (!!) than current Rust implementations which are 1+ order of magnitude faster than other languages.
Here is a low-level example of how you can use these new primitives:
use alloy_primitives::Address;
use alloy_sol_types::{sol, SolType};
// Type definition: generates a new struct that implements `SolType`
sol! {
type MyType is uint256;
}
// Type aliases
type B32 = sol! { bytes32 };
// This is equivalent to the following:
// type B32 = alloy_sol_types::sol_data::Bytes<32>;
type SolArrayOf<T> = sol! { T[] };
type SolTuple = sol! { tuple(address, bytes, string) };
let _ = <sol!(bool)>::encode_single(&true);
let _ = B32::encode_single(&[0; 32]);
let _ = SolArrayOf::<sol!(bool)>::encode_single(&vec![true, false]);
let _ = SolTuple::encode_single(&(Address::ZERO, vec![0; 32], "hello".to_string()));
Here's a higher-level example, showing a roundtrip ABI encoding of an ERC20 transfer:
use alloy_primitives::{Address, U256};
use alloy_sol_types::{sol, SolCall};
use hex_literal::hex;
sol! {
#[derive(Debug, PartialEq)]
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
}
}
// random mainnet ERC20 transfer
// https://etherscan.io/tx/0x947332ff624b5092fb92e8f02cdbb8a50314e861a4b39c29a286b3b75432165e
let data = hex!(
"a9059cbb"
"0000000000000000000000008bc47be1e3abbaba182069c89d08a61fa6c2b292"
"0000000000000000000000000000000000000000000000000000000253c51700"
);
let expected = IERC20::transferCall {
to: Address::from(hex!("8bc47be1e3abbaba182069c89d08a61fa6c2b292")),
amount: U256::from(9995360000_u64),
};
assert_eq!(data[..4], IERC20::transferCall::SELECTOR);
let decoded = IERC20::IERC20Calls::decode(&data, true).unwrap();
assert_eq!(decoded, IERC20::IERC20Calls::transfer(expected));
assert_eq!(decoded.encode(), data);
Alloy is really powerful!
These crates will act as the solid foundation we’ve always wanted for Ethereum in Rust, informed by the lessons from our last 3 years of Rust Ethereum engineering. The code for these crates is under active development on github. We love new contributors. The pre-1.0.0 version of these crates are available on [crates.io](https://crates.
io/crates/alloy-primitives), and docs.rs.
PRs included in this release:
- feature: add uint as submodule by @prestwich in #1
- Prestwich/dyn enc by @prestwich in #2
- Generic signed int implementation by @prestwich in #3
- Implement ABI for I256 by @prestwich in #5
- Prestwich/int-edge-cases by @prestwich in #4
- Dynamic EIP-712 by @prestwich in #6
- ci: add initial Continuous Integration Workflows using GitHub® Actions™ by @DaniPopes in #8
- feat: improve macros by @DaniPopes in #7
- Prestwich/ingest encode type by @prestwich in #15
- chore: use workspace.{package,dependencies} by @DaniPopes in #17
- fix: add alloc features in no_std by @prestwich in #18
- Add Address w/ checksum support to
primitives
by @prestwich in #19 - chore: add missing deny.toml by @DaniPopes in #23
- chore: update error type by @DaniPopes in #22
- Sol Type re-factoring by @prestwich in #20
- fix: sol macro parsing and expansion by @DaniPopes in #21
- feat: use
const-hex
instead ofhex
by @DaniPopes in #25 - feature: standard solidity revert & panic by @prestwich in #28
- feat(sol-type-parser): parse and expand custom errors and functions by @DaniPopes in #24
- doc: brief doc on the type system by @prestwich in #26
- refactor: remerge SolType and SolDataType by @prestwich in #30
- chore: use crates.io uint, move crates to
crates/*
by @DaniPopes in #31 - doc: main lib README by @prestwich in #34
- chore: pre-release mega cleanup by @DaniPopes in #35
- Prestwich/crate readmes by @prestwich in #41
- fmt: add rustfmt.toml by @DaniPopes in #42
- chore: add fmt commit to .git-blame-ignore-revs by @DaniPopes in #43
- doc: note on no_std support by @prestwich in #44
- chore: rename crates by @DaniPopes in #45
- ci: fix rustdoc job, docs by @DaniPopes in #46
- fix: type check int for dirty high bytes by @prestwich in #47
- fix: hex breaking change by @DaniPopes in #50
- feat: add PanicKind enum by @DaniPopes in #54
- fix: rlp impls by @DaniPopes in #56
- feat: primitive utils and improvements by @DaniPopes in #52
- doc: Contributing doc by @prestwich in #49
- feat: support function overloading in
sol!
by @DaniPopes in #53 - refactor:
sol!
AST and macro expansion by @DaniPopes in #61 - ci: fix dep job, add feature-checks job by @DaniPopes in #64
- feat: move Solidity syn AST to
syn-solidity
by @DaniPopes in #63 - fix: extra-traits in syn-solidity by @prestwich in #65
- chore: remove syn "full" feature by @DaniPopes in #66
- chore: enable
feature(doc_cfg, doc_auto_cfg)
by @DaniPopes in #67 - chore: rename to Alloy by @DaniPopes in #69
- feat/perf: abi benchmarks by @DaniPopes in #57
- feat: syn-solidity visitors by @DaniPopes in #68
- chore: feature-gate
getrandom
, document in README.md by @DaniPopes in #71 - docs: rlp-derive README.md by @DaniPopes in #70
- ci: add WASM job by @DaniPopes in #76
- test: bless tests after updating to syn 2.0.19 by @DaniPopes in #79
- Revert "test: bless tests after updating to syn 2.0.19" by @DaniPopes in #80
- feature: abi-json crate by @prestwich in #78
- feat:
sol!
contracts by @DaniPopes in #77 - fix: make detokenize infallible by @prestwich in #86
- test: add more json abi tests by @DaniPopes in #89
- refactor: implement
SolType
for{Ui,I}nt<N>
andFixedBytes<N>
with const-generics by @DaniPopes in #92 - refactor: change is_dynamic to a const DYNAMIC by @prestwich in #99
- fix: add
repr(C)
to json-abi items by @DaniPopes in #100 - feat: issue and PR templates #33 by @prestwich in #93
- feat: Solidity events support by @DaniPopes in #83
- feat: json-abi event selector by @DaniPopes in #104
- feature: compute encoded size statically where possible by @prestwich in #105
- feat: more FixedBytes impls by @DaniPopes in #111
- feat: make
TokenType::is_dynamic
a constant by @DaniPopes in #114 - feat: improve SolType tuples by @DaniPopes in #115
- chore: add CODEOWNERS, update deny.toml and ci.yml by @DaniPopes in #117
- chore: clean up features by @DaniPopes in #116
- refactor: sol-macro expansion by @DaniPopes in #113
- perf: improve rlp, update Address methods by @DaniPopes in #118
- feat: finish high-level Solidity parser by @DaniPopes in #119
- fix: (u)int tokenization by @DaniPopes in #123
- refactor: Lifetimes for token types by @prestwich in #120
- fix: links in readme by @prestwich in #128
- chore: typo fix by @onbjerg in #129
- fix: fmt by @prestwich in #130
- chore: typo fix by @onbjerg in #131
- chore: typos by @DaniPopes in #132
- feat: add
Encodable
trait by @prestwich in #121 - fix: remove to_rust from most traits by @prestwich in #133
- chore: add .gitattributes by @DaniPopes in #135
- feat: unify json-abi params impls by @DaniPopes in #136
- chore: add logo to all crates, add @gakonst to CODEOWNERS by @DaniPopes in #138
- Release 0.2.0 by @gakonst in #139
New Contributors
Full Changelog: https://github.com/alloy-rs/core/commits/v0.2.0
(This was going to be a v0.1.0 release, but we did an internal one first)