Advanced Usage
This page covers advanced patterns for working with interoperable addresses — validation, checksums, error handling, round-trip conversions, and working directly with each layer.
For an explanation of the two-layer architecture and the standards, see Concepts.
Computing Checksums
Checksums are always calculated from the binary address, even if not provided:
import { computeChecksum, parseName } from "@wonderland/interop-addresses";
// Compute checksum from name
const checksum = await computeChecksum("vitalik.eth@eip155:1");
// Returns: "4CA88C9C"
// Parse with checksum validation
const result = await parseName("vitalik.eth@eip155:1");
// result.meta.checksum - always calculated
// result.meta.checksumMismatch - present if provided checksum didn't match
Validation
The package provides methods to validate addresses:
import {
isValidBinaryAddress,
isValidInteropAddress,
isValidInteroperableName,
} from "@wonderland/interop-addresses";
// Validate any interop address (binary or name)
const isValid = await isValidInteropAddress("vitalik.eth@eip155:1", {
validateChecksumFlag: true,
});
// Validate specifically interoperable names
const isValidName = await isValidInteroperableName("vitalik.eth@eip155:1", {
validateChecksumFlag: true,
});
// Validate binary addresses (synchronous)
const isValidBinary = isValidBinaryAddress(
"0x00010000010114d8da6bf26964af9d7eed9e03e53415d37aa96045",
);
Working with Chain References
import { isValidChain, isValidChainType, resolveChain } from "@wonderland/interop-addresses";
// Validate chain type
const isValid = isValidChainType("eip155"); // true
// Validate chain reference
const isValidChainRef = isValidChain("eip155", "1"); // true
// Resolve chain (handles shortname resolution, validation, etc.)
const resolved = await resolveChain({ chainReference: "eth" });
// Returns: { chainType: "eip155", chainReference: "1" }
Error Handling
The package includes specific error types for better error handling:
import {
ENSLookupFailed,
ENSNotFound,
InvalidAddress,
InvalidChainType,
InvalidInteroperableAddress,
InvalidInteroperableName,
UnsupportedChainType,
} from "@wonderland/interop-addresses";
try {
const result = await parseName("invalid.eth@eip155:1");
} catch (error) {
if (error instanceof InvalidAddress) {
// Handle invalid address error
} else if (error instanceof UnsupportedChainType) {
// Handle unsupported chain type error
} else if (error instanceof ENSNotFound) {
// Handle ENS name not found
} else if (error instanceof ENSLookupFailed) {
// Handle ENS lookup failure
} else if (error instanceof InvalidInteroperableName) {
// Handle invalid interoperable name format
} else if (error instanceof InvalidChainType) {
// Handle invalid chain type
} else if (error instanceof InvalidInteroperableAddress) {
// Handle invalid interoperable address structure (validation error)
// Thrown by validateInteroperableAddress, encodeAddress, toBinaryRepresentation, formatName
}
}
Round-Trip Conversions
Name → Text → Binary → Text → Name
import {
calculateChecksum,
decodeAddress,
encodeAddress,
formatName,
isTextAddress,
parseName,
} from "@wonderland/interop-addresses";
// Start with name
const name = "vitalik.eth@eip155:1";
// Parse to get text address (default)
const parsed = await parseName(name);
const textAddr = parsed.interoperableAddress;
// Verify it's text representation
if (!isTextAddress(textAddr)) {
throw new Error("Expected text representation");
}
// Encode text address to binary
const binary = encodeAddress(textAddr, { format: "hex" });
// Decode binary back to text address
const textAddrFromBinary = decodeAddress(binary);
// Format back to name (checksum calculated automatically)
const nameFromText = formatName(textAddrFromBinary);
Text → Binary → Text (Synchronous)
import { decodeAddress, encodeAddress, isTextAddress } from "@wonderland/interop-addresses";
const textAddr = {
version: 1,
chainType: "eip155",
chainReference: "1",
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
};
// Convert to binary
const binary = encodeAddress(textAddr, { format: "hex" });
// Convert back to text
const textRoundTrip = decodeAddress(binary);
// textRoundTrip should equal textAddr (use isTextAddress to verify)
if (isTextAddress(textRoundTrip)) {
console.log(textRoundTrip.chainType); // "eip155"
console.log(textRoundTrip.chainReference); // "1"
console.log(textRoundTrip.address); // "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
}
Best Practices
-
Use type guards for type safety: Always use
isTextAddress()orisBinaryAddress()to narrow the discriminated union before accessing fields. -
Default to text representation: The default representation is "text" (more user-friendly). Use binary only when you need raw bytes.
-
Automatic conversion: Functions like
encodeAddressandformatNameaccept either representation and convert automatically - no need to manually convert first. -
Always validate addresses: Use validation methods before using addresses in production code.
-
Handle checksum mismatches: Check
result.meta.checksumMismatchwhen parsing names to detect potential issues. -
Use individual functions for tree-shaking: Import only what you need to minimize bundle size.
-
Handle errors appropriately: Use the provided error types for better error handling.
-
Use ENS names for better UX: ENS names provide a better user experience when available.
-
Convert representations explicitly when needed: Use
toBinaryRepresentation()ortoTextRepresentation()only when you need to change the representation type explicitly.
Next steps
- API Reference — complete function signatures and types
- Concepts — understand the two-layer architecture and the standards