HyperlaneGatewayAdapterLib
Title: HyperlaneGatewayAdapterLib
Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from Hyperlane (https://github.com/hyperlane-xyz/hyperlane-monorepo)
Logic + ERC-7201 storage for the Hyperlane ERC-7786 gateway adapter. sendMessage wraps the
ERC-7930 envelope with a source-minted nonce and dispatches it via the Mailbox's 4-arg dispatch
(default hook + synthesized StandardHookMetadata); handle is the Mailbox-gated delivery callback
that validates the origin domain + trusted remote, de-duplicates per (chainId, sendId), and
delivers to the ERC-7930 recipient. EVM chains only. Hyperlane routes by uint32 domain — usually
the EVM chainId but NOT guaranteed, so the map is admin-registered, never inferred.
Wire message = abi.encode(senderInteropAddr, recipientInteropAddr, innerPayload, nonce); the
Mailbox recipientAddress targets the trusted 32-byte remote, which forwards to the final recipient.
The hook metadata is Hyperlane StandardHookMetadata variant 1 synthesized INLINE (no hook-lib
dependency): variant(uint16=1) || msgValue(uint256=0) || gasLimit(uint256) || refundAddress(address = the sending user) — overpaid IGP fees refund to the user, never to the Diamond. v1 uses the
Mailbox DEFAULT ISM (no ISpecifiesInterchainSecurityModule); pinning a Lattice-custom ISM by adding
interchainSecurityModule() to the facet later is a compatible additive follow-up.
Constants
METADATA_VARIANT
StandardHookMetadata variant 1 (the only variant the default hook stack understands).
uint16 private constant METADATA_VARIANT = 1;DEFAULT_DESTINATION_GAS
handle gas limit used when a destination has no admin-configured gas limit. Sized for envelope
decode + auth + dedup + a typical receiveMessage (Hyperlane's own bare default of 50k is too
thin for the recipient hop).
uint256 internal constant DEFAULT_DESTINATION_GAS = 200_000;Functions
hyperlaneGatewayAdapterStorage
function hyperlaneGatewayAdapterStorage() internal pure returns (HyperlaneGatewayAdapterStorage storage $);Returns
| Name | Type | Description |
|---|---|---|
| $ | HyperlaneGatewayAdapterStorage |
__HyperlaneGatewayAdapter_init
Stores the Mailbox (zero reverts HyperlaneZeroMailbox — an unconfigured adapter must not
exist) and registers the gateway-source + adapter ERC-165 ids.
function __HyperlaneGatewayAdapter_init(address mailbox_) internal;Parameters
| Name | Type | Description |
|---|---|---|
| mailbox_ | address |
registerInterfaces
Writes true to the SHARED IERC7786GatewaySource ERC-165 map slot (0x11967553 → ...; same
slot the CCIP/LayerZero/Wormhole/Axelar adapters register — a Diamond mounts at most one
gateway) and to the adapter's own IHyperlaneGatewayAdapter map slot.
function registerInterfaces() internal;mailbox
function mailbox() internal view returns (address);Returns
| Name | Type | Description |
|---|---|---|
| <none> | address |
domainOf
function domainOf(uint256 chainId) internal view returns (uint32);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint32 |
chainIdOf
function chainIdOf(uint32 domain) internal view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| domain | uint32 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
trustedRemoteOf
function trustedRemoteOf(uint256 chainId) internal view returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
destGasLimitOf
function destGasLimitOf(uint256 chainId) internal view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
supportsAttribute
No sendMessage attributes are supported by this adapter (per-dest gas is admin-configured).
function supportsAttribute(bytes4) internal pure returns (bool);Parameters
| Name | Type | Description |
|---|---|---|
| _ | bytes4 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bool |
quoteFee
Quotes the Mailbox fee to send payload to recipient (ERC-7930), synthesizing the same wire
envelope (with the NEXT nonce) + StandardHookMetadata a real send would dispatch.
function quoteFee(bytes calldata recipient, bytes calldata payload) internal view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| recipient | bytes | |
| payload | bytes |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
registerDomain
Registers an EVM chainId ↔ Hyperlane domain equivalence (both directions). FAIL-LOUD identity admin: an already-mapped chainId OR domain reverts — identities are never remapped. Admin only.
function registerDomain(uint256 chainId, uint32 domain) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| domain | uint32 |
registerRemote
Sets the trusted 32-byte remote (counterpart adapter) for a chain. TUNABLE (updatable), but never zero — clearing a corridor is not supported in v1. Admin only.
function registerRemote(uint256 chainId, bytes32 remote) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| remote | bytes32 |
configureDestination
Configures a destination's handle gas limit. TUNABLE; 0 = fall back to
DEFAULT_DESTINATION_GAS at send time. Admin only.
function configureDestination(uint256 chainId, uint256 gasLimit) internal;Parameters
| Name | Type | Description |
|---|---|---|
| chainId | uint256 | |
| gasLimit | uint256 |
sendMessage
ERC-7786 source. Quotes the Mailbox fee (typed HyperlaneInsufficientFee on shortfall), then
dispatches immediately via the 4-arg dispatch, forwarding msg.value WHOLE — the default
hook refunds any surplus to the metadata refundAddress (msg.sender, the sending user), so the
Diamond never holds or spends fee funds.
No attributes are supported — any attribute reverts UnsupportedAttribute. The envelope carries a
source-owned monotonic nonce (++$._lastNonce) so the delivery id is globally unique per
(source, nonce) rather than envelope content — otherwise two byte-identical-but-distinct messages
would collide on delivery (one permanently dropped). Returns the suite-level
sendId = keccak256(abi.encode(block.chainid, nonce)); the Hyperlane messageId is surfaced via
HyperlaneMessageDispatched.
function sendMessage(bytes calldata recipient, bytes calldata payload, bytes[] calldata attributes)
internal
returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| recipient | bytes | |
| payload | bytes | |
| attributes | bytes[] |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
handle
Mailbox delivery callback: DUAL AUTH — msg.sender must be the Mailbox AND the 32-byte
sender must equal the trusted remote registered for the origin domain's chain (fail-closed on
an unregistered domain, i.e. chainId 0, or an unset remote). De-dups per (chainId, sendId),
marking BEFORE the external delivery (checks-effects-interactions), then delivers to the
ERC-7930 recipient encoded in the envelope.
The Mailbox's own delivered map is the PROTOCOL-level replay guard (process reverts on
redelivery); the per-(chainId, sendId) guard here is defense-in-depth at the suite convention
level, keyed by the source-minted nonce id every sibling adapter uses. handle is forced payable
by IMessageRecipient, but the adapter never expects value-bearing messages in v1 — stray value
reverts HyperlaneUnexpectedValue instead of being trapped in the Diamond.
function handle(uint32 origin, bytes32 sender, bytes calldata message) internal;Parameters
| Name | Type | Description |
|---|---|---|
| origin | uint32 | |
| sender | bytes32 | |
| message | bytes |
_resolveDestination
Resolves recipient's chain into (domain, trusted remote, effective gas limit).
Reverts HyperlaneUnknownDestinationChain if the domain or remote is unset. An unset gas limit
falls back to DEFAULT_DESTINATION_GAS (mirroring the per-dest admin gas of the LZ sibling, with
a default instead of a hard revert — Hyperlane's default hook prices gas from the metadata).
function _resolveDestination(HyperlaneGatewayAdapterStorage storage $, bytes calldata recipient)
private
view
returns (uint32 domain, bytes32 remote, uint256 gasLimit);Parameters
| Name | Type | Description |
|---|---|---|
| $ | HyperlaneGatewayAdapterStorage | |
| recipient | bytes |
Returns
| Name | Type | Description |
|---|---|---|
| domain | uint32 | |
| remote | bytes32 | |
| gasLimit | uint256 |
_buildMetadata
Synthesizes Hyperlane StandardHookMetadata variant 1 INLINE (no hook-lib dependency):
variant(uint16=1) || msgValue(uint256=0) || gasLimit(uint256) || refundAddress(address).
msgValue is always 0 (plain messages only in v1); refundAddress is the sending user, so
overpaid IGP fees refund there.
function _buildMetadata(uint256 gasLimit, address refundAddress) private pure returns (bytes memory);Parameters
| Name | Type | Description |
|---|---|---|
| gasLimit | uint256 | |
| refundAddress | address |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes |