ChainRegistryLib
Title: ChainRegistryLib
Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
Logic + ERC-7201 storage for the Lattice chain registry: chain identities keyed by
keccak256(abi.encodePacked(chainType, chainReference)) (EVM and non-EVM handled identically), an
informational native-id index, per-chain gateway coverage with direct/hub-routed distinction, and
addEvmChain — the one-action admin fan-out that registers an EVM chain and pushes its config into
every enabled gateway adapter LIB directly (internal calls, so msg.sender stays the admin and each
lib's own checkRole passes; NEVER external self-calls, which would break AccessControl).
COVERAGE AWARENESS, NOT ROUTING (issue #77 Q5): the registry is the config single-source-of-truth and
the coverage authority, but adapters keep their own cheap hot-path maps — the registry NEVER sits in
any adapter send path (the only cross-module reader is the OpenBridge's opt-in
minDirectCoverage gate). Hub-routed coverage (e.g. the ZetaChain adapter reaching connected chains
only via the ZEVM hub) NEVER counts toward directCoverageOf.
Constants
EVM_CHAIN_TYPE
The ERC-7930 chain type of eip-155 (EVM) chains.
bytes2 internal constant EVM_CHAIN_TYPE = 0x0000;Functions
chainRegistryStorage
function chainRegistryStorage() internal pure returns (ChainRegistryStorage storage $);Returns
| Name | Type | Description |
|---|---|---|
| $ | ChainRegistryStorage |
__ChainRegistry_init
Registers the IChainRegistry ERC-165 id. Called inside the diamond initializing window.
function __ChainRegistry_init() internal;registerInterface
Writes true to the ERC-165 map slot for IChainRegistry.
function registerInterface() internal;chainKeyOf
The chain key of any ERC-7930 chain identity.
function chainKeyOf(bytes2 chainType, bytes memory chainReference) internal pure returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | |
| chainReference | bytes |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
chainKeyEvm
The chain key of an EVM chain (eip-155 chainType + canonical minimal big-endian reference).
function chainKeyEvm(uint256 chainId) internal pure returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
_evmChainReference
The canonical minimal big-endian (no leading zeros) ERC-7930 chain reference of chainId.
Derived by round-tripping InteroperableAddress.formatEvmV1 through InteroperableAddress.parseV1
— the ONE encoding the whole repo uses; deliberately not re-implemented here.
function _evmChainReference(uint256 chainId) private pure returns (bytes memory chainReference);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| chainReference | bytes |
isRegistered
function isRegistered(bytes32 chainKey) internal view returns (bool);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bool |
chainInfoOf
function chainInfoOf(bytes32 chainKey)
internal
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
function nativeIdsOf(bytes32 chainKey) internal view returns (IChainRegistry.NativeIds memory);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | IChainRegistry.NativeIds |
gatewaysOf
function gatewaysOf(bytes32 chainKey) internal 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) internal 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; n is admin-bounded small (at most one entry per local adapter).
function directCoverageOf(bytes32 chainKey) internal view returns (uint256 direct);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| direct | uint256 |
registerChain
Registers a chain identity (EVM or non-EVM). Admin only. Re-register reverts
ChainRegistryAlreadyRegistered — chain identities are permanent, so an explicit removeChain
is deliberately absent in v1 (YAGNI; coverage entries and native ids stay mutable).
function registerChain(bytes2 chainType, bytes calldata chainReference, uint256 evmChainId) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | |
| chainReference | bytes | |
| evmChainId | uint256 |
setNativeIds
Sets the informational native ids of a registered chain. Admin only.
function setNativeIds(bytes32 chainKey, IChainRegistry.NativeIds calldata ids) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| ids | IChainRegistry.NativeIds |
setGatewayCoverage
Records (covered = true, with the given hubRouted flag) or clears (covered = false)
gateway's coverage of a registered chain. Admin only. Re-recording an existing gateway
updates its hubRouted flag.
function setGatewayCoverage(bytes32 chainKey, address gateway, bool covered, bool hubRouted) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| gateway | address | |
| covered | bool | |
| hubRouted | bool |
addEvmChain
ONE structured admin action that adds an EVM chain everywhere: registers the chain identity,
records the native ids declared by the enabled sections, fans the per-adapter config out into
every ENABLED adapter lib (direct internal calls — msg.sender stays the admin, so each lib's
own DEFAULT_ADMIN_ROLE check passes), then records the coverage entries. Admin only.
The fan-out writes each enabled adapter's ERC-7201 slots whether or not that adapter's facet is
cut into this diamond — un-hosted slots simply go unread until such a facet is cut, so leaving a
section for an un-hosted adapter disabled is the ADMIN's responsibility (no facet-existence
introspection by design). Per-adapter duplicate guards (e.g. ChainSelectorAlreadyRegistered)
bubble up unchanged and roll back the whole action.
function addEvmChain(IChainRegistry.AddEvmChainConfig calldata cfg) internal;Parameters
| Name | Type | Description |
|---|---|---|
| cfg | IChainRegistry.AddEvmChainConfig |
_registerChain
Registers the chain identity and returns its key. Reverts ChainRegistryEmptyChainReference on
an empty reference, ChainRegistryAlreadyRegistered if the identity already exists.
FAIL-CLOSED eip-155 canonicality (review finding): an EVM chainType requires a non-zero
evmChainId whose canonical minimal-big-endian reference byte-equals chainReference — a
non-minimal reference (e.g. hex"000a" for chain 10) would mint a chainKey the send-time derivation
can NEVER match, silently making coverage records unreachable. Non-EVM chainTypes require
evmChainId == 0 (the field is meaningless there).
function _registerChain(bytes2 chainType, bytes memory chainReference, uint256 evmChainId)
private
returns (bytes32 chainKey);Parameters
| Name | Type | Description |
|---|---|---|
| chainType | bytes2 | |
| chainReference | bytes | |
| evmChainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
_setNativeIds
function _setNativeIds(bytes32 chainKey, IChainRegistry.NativeIds memory ids) private;Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| ids | IChainRegistry.NativeIds |
_setGatewayCoverage
EVENT FIDELITY (review finding): the emitted event mirrors STORED state exactly so off-chain indexers reconstructing coverage from events cannot drift — a no-op removal (gateway was never covered) emits nothing, and the covered=false path always logs hubRouted=false (the flag is deleted, never stored).
function _setGatewayCoverage(bytes32 chainKey, address gateway, bool covered, bool hubRouted) private;Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 | |
| gateway | address | |
| covered | bool | |
| hubRouted | bool |
_registeredRecord
The record of chainKey, reverting ChainRegistryNotRegistered when it is not registered.
function _registeredRecord(bytes32 chainKey) private view returns (ChainRecord storage record);Parameters
| Name | Type | Description |
|---|---|---|
| chainKey | bytes32 |
Returns
| Name | Type | Description |
|---|---|---|
| record | ChainRecord |
_checkAxelarSection
Fail-closed Axelar section checks: chain7930 must be the CANONICAL chain-only ERC-7930
address of chainId (the exact bytes the Axelar adapter keys its equivalence map with —
InteroperableAddress.formatEvmV1(chainId)), and remote7930 must address chainId.
function _checkAxelarSection(uint256 chainId, IChainRegistry.AxelarSection calldata section) private pure;Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| section | IChainRegistry.AxelarSection |