IChainRegistry
Title: IChainRegistry
Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
Admin / read surface of the Lattice chain registry: a generic ERC-7201 registry of chains keyed by
their ERC-7930 chain identity (chainKey = keccak256(abi.encodePacked(chainType, chainReference)),
so EVM and non-EVM chains are supported identically), an informational native-id index per bridge
ecosystem, a per-chain gateway COVERAGE map (which local gateway adapters can reach the chain, and
whether only via an intermediate hub), and addEvmChain — the one-action admin fan-out that
registers an EVM chain and pushes its config into every enabled gateway adapter in a single call.
COVERAGE AWARENESS, NOT ROUTING (issue #77 Q5): the registry is the config single-source-of-truth and
the authority for M-of-N coverage math, but every adapter keeps its own cheap hot-path maps — the
registry NEVER sits in any adapter send path. Enforcement is opt-in on the OpenBridge side
(setMinDirectCoverage); hub-routed coverage (e.g. ZetaChain reaching connected chains only via the
ZEVM hub) NEVER counts toward DIRECT coverage. Chains cannot be removed in v1 (YAGNI — a chain identity
is permanent; coverage entries and native ids stay mutable).
Functions
chainKeyEvm
The chain key of an EVM chain: eip-155 chainType (0x0000) + the canonical minimal big-endian
chain reference (exactly the InteroperableAddress.formatEvmV1 encoding — no leading zeros).
function chainKeyEvm(uint256 chainId) external pure returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
chainKeyOf
The chain key of any ERC-7930 chain identity:
keccak256(abi.encodePacked(chainType, chainReference)).
function chainKeyOf(bytes2 chainType, bytes calldata chainReference) external pure returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | |
| chainReference | bytes |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
isRegistered
Whether chainKey is a registered chain identity.
function isRegistered(bytes32 chainKey) external view returns (bool);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bool |
chainInfoOf
The registered ERC-7930 identity of chainKey (evmChainId is 0 for non-EVM chains).
function chainInfoOf(bytes32 chainKey)
external
view
returns (bytes2 chainType, bytes memory chainReference, uint256 evmChainId);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | |
| chainReference | bytes | |
| evmChainId | uint256 |
nativeIdsOf
The informational native bridge-ecosystem ids of chainKey.
function nativeIdsOf(bytes32 chainKey) external view returns (NativeIds memory);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | NativeIds |
gatewaysOf
The gateway adapters recorded as covering chainKey (direct AND hub-routed).
function gatewaysOf(bytes32 chainKey) external view returns (address[] memory);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | address[] |
coverageOf
The total number of gateways covering chainKey (direct + hub-routed).
function coverageOf(bytes32 chainKey) external view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
directCoverageOf
The number of gateways covering chainKey DIRECTLY (hub-routed coverage never counts).
O(n) over the coverage set — admin-bounded small (one entry per local gateway adapter).
function directCoverageOf(bytes32 chainKey) external view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
registerChain
Registers a chain identity (EVM or non-EVM). Admin only. Reverts ChainRegistryAlreadyRegistered on re-register — chain identities are permanent in v1.
function registerChain(bytes2 chainType, bytes calldata chainReference, uint256 evmChainId) external;Parameters
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | The ERC-7930 chain type (0x0000 = eip-155). |
| chainReference | bytes | The ERC-7930 chain reference (for EVM chains use the canonical minimal big-endian chainId encoding, or use addEvmChain which builds it). |
| evmChainId | uint256 | The EVM chainId (informational; 0 for non-EVM chains). |
setNativeIds
Sets the informational native ids of a registered chain. Admin only.
function setNativeIds(bytes32 chainKey, NativeIds calldata ids) external;Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| ids | NativeIds |
setGatewayCoverage
Records (or clears) gateway's coverage of a registered chain. Admin only.
function setGatewayCoverage(bytes32 chainKey, address gateway, bool covered, bool hubRouted) external;Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | The registered chain key. |
| gateway | address | The local gateway adapter (non-zero). |
| covered | bool | True to record coverage, false to remove it. |
| hubRouted | bool | True when the gateway reaches the chain only via an intermediate hub (e.g. the ZetaChain ZEVM hub) — hub-routed coverage never counts toward directCoverageOf. |
addEvmChain
ONE structured admin action that adds an EVM chain everywhere: registers the chain identity (eip-155 + canonical minimal big-endian reference), records the native ids declared by the enabled sections, then fans the per-adapter config out into every ENABLED gateway adapter's own ERC-7201 storage via direct internal lib calls (msg.sender stays the admin — never external self-calls), and finally records the coverage entries. Admin only.
Reverts ChainRegistryAlreadyRegistered if the chain identity already exists. Sections for adapter facets the diamond does not host must be left disabled (see AddEvmChainConfig).
function addEvmChain(AddEvmChainConfig calldata cfg) external;Parameters
| Name | Type | Description |
|---|---|---|
| cfg | AddEvmChainConfig |
Events
ChainRegistered
Emitted when a chain identity is registered.
event ChainRegistered(bytes32 indexed chainKey, bytes2 chainType, bytes chainReference, uint256 evmChainId);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| chainType | bytes2 | |
| chainReference | bytes | |
| evmChainId | uint256 |
SetNativeIds
Emitted when a chain's informational native ids are set.
event SetNativeIds(bytes32 indexed chainKey, NativeIds ids);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| ids | NativeIds |
SetGatewayCoverage
Emitted when a gateway's coverage of a chain is set or cleared.
event SetGatewayCoverage(bytes32 indexed chainKey, address indexed gateway, bool covered, bool hubRouted);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| gateway | address | |
| covered | bool | |
| hubRouted | bool |
ChainAdded
Emitted once per successful addEvmChain fan-out (the per-adapter libs emit their own events).
event ChainAdded(bytes32 indexed chainKey, uint256 indexed chainId);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| chainId | uint256 |
Errors
ChainRegistryAlreadyRegistered
The chain identity is already registered (chain identities are permanent — no removal in v1).
error ChainRegistryAlreadyRegistered(bytes32 chainKey);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
ChainRegistryNotRegistered
The chain identity is not registered yet (register it before configuring it).
error ChainRegistryNotRegistered(bytes32 chainKey);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
ChainRegistryEmptyChainReference
The chain reference was empty (an ERC-7930 chain identity needs a reference).
error ChainRegistryEmptyChainReference();ChainRegistryZeroGateway
The coverage gateway was the zero address.
error ChainRegistryZeroGateway();ChainRegistryCoverageLengthMismatch
The coverage section's gateways and hubRouted arrays differ in length.
error ChainRegistryCoverageLengthMismatch(uint256 gateways, uint256 hubRouted);Parameters
| Name | Type | Description |
|---|---|---|
| gateways | uint256 | |
| hubRouted | uint256 |
ChainRegistryAxelarChainMismatch
The Axelar section's chain7930 is not the canonical chain-only ERC-7930 address of chainId.
error ChainRegistryAxelarChainMismatch();ChainRegistryAxelarRemoteMismatch
The Axelar section's remote7930 does not address the chainId being added.
error ChainRegistryAxelarRemoteMismatch();ChainRegistryStargateEidMismatch
The stargate section's eid contradicts the layerZero section's eid in the same config — Stargate rides LayerZero, so when both sections are enabled the eids must be equal.
error ChainRegistryStargateEidMismatch(uint32 lzEid, uint32 stargateEid);Parameters
| Name | Type | Description |
|---|---|---|
| lzEid | uint32 | |
| stargateEid | uint32 |
ChainRegistryNonCanonicalEvmReference
An eip-155 registration whose chainReference is not the canonical minimal-big-endian encoding
of evmChainId (or whose evmChainId is 0) — such a key could never match send-time derivation.
error ChainRegistryNonCanonicalEvmReference(bytes chainReference, uint256 evmChainId);Parameters
| Name | Type | Description |
|---|---|---|
| chainReference | bytes | |
| evmChainId | uint256 |
ChainRegistryEvmChainIdOnNonEvmChain
A non-EVM registration supplied a non-zero evmChainId (meaningless for non-EVM chainTypes).
error ChainRegistryEvmChainIdOnNonEvmChain(uint256 evmChainId);Parameters
| Name | Type | Description |
|---|---|---|
| evmChainId | uint256 |
Structs
NativeIds
Per-chain native identifiers of the major bridge ecosystems. Purely an INFORMATIONAL indexing layer (0 / empty = unset) — adapters keep their own authoritative hot-path maps.
struct NativeIds {
/// @notice Chainlink CCIP chain selector (0 = unset).
uint64 ccipSelector;
/// @notice LayerZero v2 endpoint id (0 = unset).
uint32 lzEid;
/// @notice Wormhole chain id (0 = unset).
uint16 wormholeId;
/// @notice Circle CCTP domain (0 = unset; NOTE domain 0 is Ethereum — rely on the CCTP adapter's own
/// registered flag for authoritative reads, this field is informational).
uint32 cctpDomain;
/// @notice Axelar chain name (empty = unset).
string axelarName;
/// @notice Hyperlane domain (0 = unset; usually — but NOT guaranteed — the EVM chainId). APPENDED.
uint32 hyperlaneDomain;
}Properties
| Name | Type | Description |
|---|---|---|
| ccipSelector | uint64 | |
| lzEid | uint32 | |
| wormholeId | uint16 | |
| cctpDomain | uint32 | |
| axelarName | string | |
| hyperlaneDomain | uint32 |
CcipSection
CCIP fan-out section of AddEvmChainConfig (disabled sections are skipped entirely).
struct CcipSection {
bool enabled;
uint64 selector;
address remoteGateway;
uint256 gasLimit;
bool allowOutOfOrderExecution;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| selector | uint64 | |
| remoteGateway | address | |
| gasLimit | uint256 | |
| allowOutOfOrderExecution | bool |
LayerZeroSection
LayerZero v2 fan-out section of AddEvmChainConfig.
struct LayerZeroSection {
bool enabled;
uint32 eid;
bytes32 peer;
uint128 gas;
uint128 msgValue;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| eid | uint32 | |
| peer | bytes32 | |
| gas | uint128 | |
| msgValue | uint128 |
WormholeSection
Wormhole fan-out section of AddEvmChainConfig.
struct WormholeSection {
bool enabled;
uint16 wormholeId;
address remote;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| wormholeId | uint16 | |
| remote | address |
AxelarSection
Axelar fan-out section of AddEvmChainConfig. chain7930 MUST be the canonical chain-only
ERC-7930 address of the chain being added (InteroperableAddress.formatEvmV1(chainId) — the
exact bytes the Axelar adapter keys its equivalence map with) and remote7930 the full ERC-7930
address of the remote gateway ON that chain; both are validated against chainId.
struct AxelarSection {
bool enabled;
string axelarName;
bytes remote7930;
bytes chain7930;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| axelarName | string | |
| remote7930 | bytes | |
| chain7930 | bytes |
ZetaSection
ZetaChain fan-out section of AddEvmChainConfig (remoteApp is the ZEVM universal app).
struct ZetaSection {
bool enabled;
address remoteApp;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| remoteApp | address |
OpL2ToL2Section
OP Superchain L2-to-L2 fan-out section of AddEvmChainConfig.
struct OpL2ToL2Section {
bool enabled;
address remoteAdapter;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| remoteAdapter | address |
CctpSection
Circle CCTP fan-out section of AddEvmChainConfig.
struct CctpSection {
bool enabled;
uint32 domain;
uint256 maxFee;
uint32 minFinalityThreshold;
bytes32 destinationCaller;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| domain | uint32 | |
| maxFee | uint256 | |
| minFinalityThreshold | uint32 | |
| destinationCaller | bytes32 |
HyperlaneSection
Hyperlane fan-out section of AddEvmChainConfig (remote is the 32-byte counterpart adapter;
gasLimit 0 = the adapter's default handle gas).
struct HyperlaneSection {
bool enabled;
uint32 domain;
bytes32 remote;
uint256 gasLimit;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| domain | uint32 | |
| remote | bytes32 | |
| gasLimit | uint256 |
StargateSection
Stargate token-bridge fan-out section of AddEvmChainConfig. Stargate rides LayerZero, so
eid equals the LayerZero section's eid for the same chain — recorded in the Stargate
adapter's OWN chainId ⇄ eid map (adapters never share hot-path storage; no separate NativeIds
field — NativeIds.lzEid is the informational record).
struct StargateSection {
bool enabled;
uint32 eid;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| eid | uint32 |
HyperbridgeSection
Hyperbridge (ISMP) fan-out section of AddEvmChainConfig. The destination state machine id is
DERIVED from chainId as the canonical bytes("EVM-" + chainId) — never caller-supplied
(fail-closed); remoteModule is the counterpart adapter module on the chain being added and
timeout the per-destination dispatch timeout in seconds (0 = no explicit timeout — the
host's default handling).
struct HyperbridgeSection {
bool enabled;
bytes remoteModule;
uint64 timeout;
}Properties
| Name | Type | Description |
|---|---|---|
| enabled | bool | |
| remoteModule | bytes | |
| timeout | uint64 |
CoverageSection
Coverage entries recorded for the new chain (parallel arrays; empty = no coverage recorded).
struct CoverageSection {
address[] gateways;
bool[] hubRouted;
}Properties
| Name | Type | Description |
|---|---|---|
| gateways | address[] | |
| hubRouted | bool[] |
AddEvmChainConfig
The one-action add-chain config: the EVM chainId plus one OPTIONAL section per gateway
adapter, each guarded by an enabled flag so any subset fans out. A section for an adapter
facet the diamond does not host MUST be left disabled by the admin (the fan-out writes that
adapter's ERC-7201 slots regardless — they would simply go unread until such a facet is cut).
struct AddEvmChainConfig {
uint256 chainId;
CcipSection ccip;
LayerZeroSection layerZero;
WormholeSection wormhole;
AxelarSection axelar;
ZetaSection zeta;
OpL2ToL2Section opL2ToL2;
CctpSection cctp;
HyperlaneSection hyperlane;
StargateSection stargate;
HyperbridgeSection hyperbridge;
CoverageSection coverage;
}Properties
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| ccip | CcipSection | |
| layerZero | LayerZeroSection | |
| wormhole | WormholeSection | |
| axelar | AxelarSection | |
| zeta | ZetaSection | |
| opL2ToL2 | OpL2ToL2Section | |
| cctp | CctpSection | |
| hyperlane | HyperlaneSection | |
| stargate | StargateSection | |
| hyperbridge | HyperbridgeSection | |
| coverage | CoverageSection |