Documentation Index
Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
Use this file to discover all available pages before exploring further.
Domain
EIP-712 domain separator structure - creates domain-specific signature contexts for dApps.
Overview
Domain defines the context for EIP-712 signatures. It prevents replay attacks by ensuring signatures are valid only within a specific domain (contract, chain, or dApp). All EIP-712 signatures include a domain separator.
Type Definition
type DomainType = {
readonly name?: string; // dApp name
readonly version?: string; // Domain version
readonly chainId?: ChainIdType; // EIP-155 chain ID
readonly verifyingContract?: AddressType; // Contract address
readonly salt?: HashType; // Salt for disambiguation
};
At least one field must be defined.
Usage
Create Domain
import * as Domain from './primitives/Domain/index.js';
const domain = Domain.from({
name: 'MyDApp',
version: '1',
chainId: 1,
verifyingContract: '0x123...',
});
Compute Domain Separator Hash
import { keccak256 } from './crypto/keccak256/index.js';
const domainSep = Domain.toHash(domain, { keccak256 });
console.log(DomainSeparator.toHex(domainSep));
Minimal Domain
// Name only
const domain = Domain.from({ name: 'MyDApp' });
// Contract only
const domain = Domain.from({
verifyingContract: '0x123...'
});
Domain Fields
name
dApp or protocol name. Used to distinguish different applications.
version
Domain version. Increment when contract logic changes.
chainId
EIP-155 chain ID. Prevents cross-chain replay attacks.
{ chainId: 1 } // Ethereum mainnet
{ chainId: 137 } // Polygon
verifyingContract
Contract address that will verify signatures. Prevents cross-contract replay.
{ verifyingContract: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' }
salt
Additional entropy for disambiguation. Rarely used.
Encoding
Type Encoding
const typeString = Domain.encodeType('EIP712Domain', {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
});
// 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
Data Encoding
const encoded = Domain.encodeData(
'EIP712Domain',
domain,
types,
{ keccak256 }
);
Examples
ERC-20 Permit
const domain = Domain.from({
name: 'USD Coin',
version: '2',
chainId: 1,
verifyingContract: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
});
Uniswap Permit2
const domain = Domain.from({
name: 'Permit2',
chainId: 1,
verifyingContract: '0x000000000022D473030F116dDEE9F6B43aC78BA3',
});
Custom dApp
const domain = Domain.from({
name: 'MyDeFiProtocol',
version: '1.0',
chainId: 1,
verifyingContract: '0x123...',
});
Security
Prevent Replay Attacks
Domain separators prevent signatures from being replayed:
- Cross-contract: Different
verifyingContract addresses
- Cross-chain: Different
chainId values
- Cross-version: Different
version strings
Best Practices
- Always include chainId - Prevents cross-chain replay
- Always include verifyingContract - Prevents cross-contract replay
- Use semantic versioning - Clear version tracking
- Don’t change domain - Breaks existing signatures
Error Handling
Domain operations throw typed errors for precise error handling:
InvalidDomainError
Thrown when a domain is invalid (e.g., has no fields defined).
import * as Domain from './primitives/Domain/index.js';
import { InvalidDomainError } from './primitives/Domain/errors.js';
try {
Domain.from({});
} catch (e) {
if (e instanceof InvalidDomainError) {
console.log(e.name); // "InvalidDomainError"
console.log(e.code); // "INVALID_DOMAIN"
console.log(e.value); // The invalid domain object
console.log(e.expected); // "valid EIP-712 domain"
}
}
InvalidDomainTypeError
Thrown when a type is not found in the types object during encoding.
import { InvalidDomainTypeError } from './primitives/Domain/errors.js';
try {
Domain.encodeData('NonExistent', data, types, { keccak256 });
} catch (e) {
if (e instanceof InvalidDomainTypeError) {
console.log(e.name); // "InvalidDomainTypeError"
console.log(e.code); // "INVALID_DOMAIN_TYPE"
}
}
InvalidEIP712ValueError
Thrown when EIP-712 value encoding fails (e.g., wrong type, invalid size).
import { InvalidEIP712ValueError } from './primitives/Domain/errors.js';
try {
Domain.encodeValue('uint512', value, types, { keccak256 }); // Invalid size
} catch (e) {
if (e instanceof InvalidEIP712ValueError) {
console.log(e.name); // "InvalidEIP712ValueError"
console.log(e.code); // "INVALID_EIP712_VALUE"
}
}
Specification
See Also