A Zig implementation of ENS (Ethereum Name Service) name normalization.
z-ens-normalize
is a robust Zig library for normalizing and validating ENS names according to ENSIP-15 specifications. It handles Unicode normalization, validation, and beautification of ENS names ensuring correct, consistent and idempotent behavior.
- Zig 0.14.0 or later
Install the dependency using the Zig CLI:
zig fetch --save https://github.com/evmts/z-ens-normalize/archive/main.tar.gz
This will automatically add the dependency to your build.zig.zon
file.
Then in your build.zig
:
const z_ens_normalize = b.dependency("z_ens_normalize", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("ens_normalize", z_ens_normalize.module("ens_normalize"));
To install a specific version or tag:
zig fetch --save https://github.com/evmts/z-ens-normalize/archive/v0.1.0.tar.gz
git clone https://github.com/evmts/z-ens-normalize.git
cd z-ens-normalize
zig build
const std = @import("std");
const ens_normalize = @import("ens_normalize");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Using normalizer to reuse preloaded data
var normalizer = try ens_normalize.EnsNameNormalizer.init(allocator);
defer normalizer.deinit();
const name = "🅰️🅱.eth";
const processed = try normalizer.process(name);
defer processed.deinit();
const beautified_name = try processed.beautify();
defer allocator.free(beautified_name);
const normalized_name = try processed.normalize();
defer allocator.free(normalized_name);
std.debug.print("Original: {s}\n", .{name});
std.debug.print("Normalized: {s}\n", .{normalized_name});
std.debug.print("Beautified: {s}\n", .{beautified_name});
// Using normalize directly
const normalized = try normalizer.normalize("Levvv.eth");
defer allocator.free(normalized);
std.debug.print("Direct normalize: {s}\n", .{normalized});
// Handling errors
const invalid_result = normalizer.normalize("Levvv..eth");
if (invalid_result) |result| {
defer allocator.free(result);
std.debug.print("Unexpected success: {s}\n", .{result});
} else |err| {
std.debug.print("Expected error: {}\n", .{err});
}
}
For simple one-off operations, you can use the convenience functions:
const std = @import("std");
const ens_normalize = @import("ens_normalize");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Direct normalization
const normalized = try ens_normalize.normalize(allocator, "Example.eth");
defer allocator.free(normalized);
// Direct beautification
const beautified = try ens_normalize.beautify_fn(allocator, "example.eth");
defer allocator.free(beautified);
// Full processing
const processed = try ens_normalize.process(allocator, "Example.eth");
defer processed.deinit();
}
The crate contains several types of tests:
- Unit tests
- Integration (e2e) tests --
tests/
- Validation ENS docs tests --
tests/ens_tests.zig
To run all tests:
zig build test
To run specific test files:
zig test tests/ens_tests.zig
zig build
This project also provides a C-compatible interface:
zig build c-lib
For development with debug information:
zig build -Doptimize=Debug
- Tokenization
- Normalization
- Beautification
- ENSIP-15 Validation Tests
- NSM (Non-Spacing Mark) Validation
- Combining Marks Validation
- Basic Confusable Detection
- Trie-based Emoji Matching - See design doc for implementation plan
- Unicode Normalization Tests
- Fenced Character Validation
- Enhanced Error Types (matching Java reference)
- CLI to update
specs.json
andnf.json
- analog of ens_cure function
- analog of ens_normalizations function
- Trie-based Emoji Matching: Replace current O(n²) hash map emoji matching with O(n) trie-based approach following Java reference implementation. See detailed design document for:
- Complete implementation plan with Zig code examples
- Performance analysis and benchmarking strategy
- Comprehensive fuzz testing approach
- Test cases extracted from Java reference implementation
- Memory safety considerations and migration strategy
- Enhanced Error Types: Add specific error types matching Java reference (NSM_DUPLICATE, CM_AFTER_EMOJI, etc.)
- Fenced Character Validation: Complete implementation of fenced character detection and validation
- Performance Optimization: Memory pool allocation for frequently allocated structures
This project is licensed under the MIT License - see the LICENSE file for details.