Crosschain

Gateways are contracts that enable cross-chain communication. These can either be a message source or a destination according to ERC-7786.

  • ERC7786Receiver: ERC-7786 cross-chain message receiver.

  • ERC7786Aggregator: ERC-7786 "N out of M" gateway. Sends a message through M gateways and executes on the destination if N received it.

Developers can access interoperability protocols through gateway adapters. The library includes the following gateway adapters:

Gateways

ERC7786Aggregator

import "@openzeppelin/community-contracts/crosschain/ERC7786Aggregator.sol";

N of M gateway: Sends your message through M independent gateways. It will be delivered to the receiver by an equivalent aggregator on the destination chain if N of the M gateways agree.

Functions
  • constructor(owner_, gateways_, threshold_)

  • supportsAttribute()

  • sendMessage(destinationChain, receiver, payload, attributes)

  • executeMessage(, sourceChain, sender, payload, attributes)

  • getGateways()

  • getThreshold()

  • getRemoteAggregator(caip2)

  • addGateway(gateway)

  • removeGateway(gateway)

  • setThreshold(newThreshold)

  • registerRemoteAggregator(caip2, aggregator)

  • pause()

  • unpause()

  • sweep(to)

  • _addGateway(gateway)

  • _removeGateway(gateway)

  • _setThreshold(newThreshold)

  • _registerRemoteAggregator(caip2, aggregator)

Pausable
  • paused()

  • _requireNotPaused()

  • _requirePaused()

  • _pause()

  • _unpause()

Ownable
  • owner()

  • _checkOwner()

  • renounceOwnership()

  • transferOwnership(newOwner)

  • _transferOwnership(newOwner)

Events
  • OutboxDetails(outboxId, outbox)

  • Received(receiveId, gateway)

  • ExecutionSuccess(receiveId)

  • ExecutionFailed(receiveId)

  • GatewayAdded(gateway)

  • GatewayRemoved(gateway)

  • ThresholdUpdated(threshold)

  • RemoteRegistered(chainId, aggregator)

Pausable
  • Paused(account)

  • Unpaused(account)

Ownable
  • OwnershipTransferred(previousOwner, newOwner)

IERC7786GatewaySource
  • MessagePosted(outboxId, sender, receiver, payload, attributes)

Errors
  • ERC7786AggregatorValueNotSupported()

  • ERC7786AggregatorInvalidCrosschainSender()

  • ERC7786AggregatorAlreadyExecuted()

  • ERC7786AggregatorRemoteNotRegistered(caip2)

  • ERC7786AggregatorGatewayAlreadyRegistered(gateway)

  • ERC7786AggregatorGatewayNotRegistered(gateway)

  • ERC7786AggregatorThresholdViolation()

  • ERC7786AggregatorInvalidExecutionReturnValue()

  • RemoteAlreadyRegistered(chainId)

Pausable
  • EnforcedPause()

  • ExpectedPause()

Ownable
  • OwnableUnauthorizedAccount(account)

  • OwnableInvalidOwner(owner)

IERC7786GatewaySource
  • UnsupportedAttribute(selector)

constructor(address owner_, address[] gateways_, uint8 threshold_) public

supportsAttribute(bytes4) → bool public

Getter to check whether an attribute is supported or not.

sendMessage(string destinationChain, string receiver, bytes payload, bytes[] attributes) → bytes32 outboxId public

Using memory instead of calldata avoids stack too deep errors

executeMessage(string, string sourceChain, string sender, bytes payload, bytes[] attributes) → bytes4 public

This function serves a dual purpose:

It will be called by ERC-7786 gateways with message coming from the the corresponding aggregator on the source chain. These "signals" are tracked until the threshold is reached. At that point the message is sent to the destination.

It can also be called by anyone (including an ERC-7786 gateway) to retry the execution. This can be useful if the automatic execution (that is triggered when the threshold is reached) fails, and someone wants to retry it.

When a message is forwarded by a known gateway, a Received event is emitted. If a known gateway calls this function more than once (for a given message), only the first call is counts toward the threshold and emits an Received event.

This function revert if:

  • the message is not properly formatted or does not originate from the registered aggregator on the source chain.

  • someone tries re-execute a message that was already successfully delivered. This includes gateways that call this function a second time with a message that was already executed.

  • the execution of the message (on the {IERC7786Receiver} receiver) is successful but fails to return the executed value.

This function does not revert if:

  • A known gateway delivers a message for the first time, and that message was already executed. In that case the message is NOT re-executed, and the correct "magic value" is returned.

  • The execution of the message (on the {IERC7786Receiver} receiver) reverts. In that case a ExecutionFailed event is emitted.

This function emits:

  • Received when a known ERC-7786 gateway delivers a message for the first time.

  • ExecutionSuccess when a message is successfully delivered to the receiver.

  • ExecutionFailed when a message delivery to the receiver reverted (for example because of OOG error).

interface requires this function to be payable. Even if we don’t expect any value, a gateway may pass some value for unknown reason. In that case we want to register this gateway having delivered the message and not revert. Any value accrued that way can be recovered by the admin using the sweep function.

getGateways() → address[] public

getThreshold() → uint8 public

getRemoteAggregator(string caip2) → string public

addGateway(address gateway) public

removeGateway(address gateway) public

setThreshold(uint8 newThreshold) public

registerRemoteAggregator(string caip2, string aggregator) public

pause() public

unpause() public

sweep(address payable to) public

Recovery method in case value is ever received through executeMessage

_addGateway(address gateway) internal

_removeGateway(address gateway) internal

_setThreshold(uint8 newThreshold) internal

_registerRemoteAggregator(string caip2, string aggregator) internal

OutboxDetails(bytes32 indexed outboxId, struct ERC7786Aggregator.Outbox[] outbox) event

Received(bytes32 indexed receiveId, address gateway) event

ExecutionSuccess(bytes32 indexed receiveId) event

ExecutionFailed(bytes32 indexed receiveId) event

GatewayAdded(address indexed gateway) event

GatewayRemoved(address indexed gateway) event

ThresholdUpdated(uint8 threshold) event

RemoteRegistered(string chainId, string aggregator) event

ERC7786AggregatorValueNotSupported() error

ERC7786AggregatorInvalidCrosschainSender() error

ERC7786AggregatorAlreadyExecuted() error

ERC7786AggregatorRemoteNotRegistered(string caip2) error

ERC7786AggregatorGatewayAlreadyRegistered(address gateway) error

ERC7786AggregatorGatewayNotRegistered(address gateway) error

ERC7786AggregatorThresholdViolation() error

ERC7786AggregatorInvalidExecutionReturnValue() error

RemoteAlreadyRegistered(string chainId) error

Clients

ERC7786Receiver

import "@openzeppelin/community-contracts/crosschain/utils/ERC7786Receiver.sol";

Base implementation of an ERC-7786 compliant cross-chain message receiver.

This abstract contract exposes the executeMessage function that is used for communication with (one or multiple) destination gateways. This contract leaves two functions unimplemented:

_isKnownGateway, an internal getter used to verify whether an address is recognised by the contract as a valid ERC-7786 destination gateway. One or multiple gateway can be supported. Note that any malicious address for which this function returns true would be able to impersonate any account on any other chain sending any message.

_processMessage, the internal function that will be called with any message that has been validated.

Functions
  • executeMessage(messageId, source, sender, payload, attributes)

  • _isKnownGateway(instance)

  • _processMessage(gateway, messageId, sourceChain, sender, payload, attributes)

Errors
  • ERC7786ReceiverInvalidGateway(gateway)

  • ERC7786ReceivePassiveModeValue()

executeMessage(string messageId, string source, string sender, bytes payload, bytes[] attributes) → bytes4 public

Endpoint for receiving cross-chain message.

_isKnownGateway(address instance) → bool internal

Virtual getter that returns whether an address is a valid ERC-7786 gateway.

_processMessage(address gateway, string messageId, string sourceChain, string sender, bytes payload, bytes[] attributes) internal

Virtual function that should contain the logic to execute when a cross-chain message is received.

ERC7786ReceiverInvalidGateway(address gateway) error

ERC7786ReceivePassiveModeValue() error

Adapters

Axelar

AxelarGatewayBase

import "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayBase.sol";

Base implementation of a cross-chain gateway adapter for the Axelar Network.

This contract allows developers to register equivalence between chains (i.e. CAIP-2 chain identifiers to Axelar chain identifiers) and remote gateways (i.e. gateways on other chains) to facilitate cross-chain communication.

Functions
  • constructor(_gateway)

  • getEquivalentChain(input)

  • getRemoteGateway(caip2)

  • registerChainEquivalence(caip2, axelarSupported)

  • registerRemoteGateway(caip2, remoteGateway)

Ownable
  • owner()

  • _checkOwner()

  • renounceOwnership()

  • transferOwnership(newOwner)

  • _transferOwnership(newOwner)

Events
  • RegisteredRemoteGateway(caip2, gatewayAddress)

  • RegisteredChainEquivalence(caip2, destinationChain)

Ownable
  • OwnershipTransferred(previousOwner, newOwner)

Errors
  • UnsupportedChain(caip2)

  • ChainEquivalenceAlreadyRegistered(caip2)

  • RemoteGatewayAlreadyRegistered(caip2)

Ownable
  • OwnableUnauthorizedAccount(account)

  • OwnableInvalidOwner(owner)

Internal Variables
  • contract IAxelarGateway _axelarGateway

constructor(contract IAxelarGateway _gateway) internal

Sets the local gateway address (i.e. Axelar’s official gateway for the current chain).

getEquivalentChain(string input) → string output public

Returns the equivalent chain given an id that can be either CAIP-2 or an Axelar network identifier.

getRemoteGateway(string caip2) → string remoteGateway public

Returns the address string of the remote gateway for a given CAIP-2 chain identifier.

registerChainEquivalence(string caip2, string axelarSupported) public

Registers a chain equivalence between a CAIP-2 chain identifier and an Axelar network identifier.

registerRemoteGateway(string caip2, string remoteGateway) public

Registers the address string of the remote gateway for a given CAIP-2 chain identifier.

RegisteredRemoteGateway(string caip2, string gatewayAddress) event

A remote gateway has been registered for a chain.

RegisteredChainEquivalence(string caip2, string destinationChain) event

A chain equivalence has been registered.

UnsupportedChain(string caip2) error

Error emitted when an unsupported chain is queried.

ChainEquivalenceAlreadyRegistered(string caip2) error

RemoteGatewayAlreadyRegistered(string caip2) error

contract IAxelarGateway _axelarGateway internal

Axelar’s official gateway for the current chain.

AxelarGatewaySource

import "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewaySource.sol";

Implementation of an ERC-7786 gateway source adapter for the Axelar Network.

The contract provides a way to send messages to a remote chain via the Axelar Network using the sendMessage function.

Functions
  • supportsAttribute()

  • sendMessage(destinationChain, receiver, payload, attributes)

AxelarGatewayBase
  • getEquivalentChain(input)

  • getRemoteGateway(caip2)

  • registerChainEquivalence(caip2, axelarSupported)

  • registerRemoteGateway(caip2, remoteGateway)

Ownable
  • owner()

  • _checkOwner()

  • renounceOwnership()

  • transferOwnership(newOwner)

  • _transferOwnership(newOwner)

Events
AxelarGatewayBase
  • RegisteredRemoteGateway(caip2, gatewayAddress)

  • RegisteredChainEquivalence(caip2, destinationChain)

Ownable
  • OwnershipTransferred(previousOwner, newOwner)

IERC7786GatewaySource
  • MessagePosted(outboxId, sender, receiver, payload, attributes)

Errors
  • UnsupportedNativeTransfer()

AxelarGatewayBase
  • UnsupportedChain(caip2)

  • ChainEquivalenceAlreadyRegistered(caip2)

  • RemoteGatewayAlreadyRegistered(caip2)

Ownable
  • OwnableUnauthorizedAccount(account)

  • OwnableInvalidOwner(owner)

IERC7786GatewaySource
  • UnsupportedAttribute(selector)

supportsAttribute(bytes4) → bool public

Getter to check whether an attribute is supported or not.

sendMessage(string destinationChain, string receiver, bytes payload, bytes[] attributes) → bytes32 outboxId external

Endpoint for creating a new message. If the message requires further (gateway specific) processing before it can be sent to the destination chain, then a non-zero outboxId must be returned. Otherwise, the message MUST be sent and this function must return 0.

UnsupportedNativeTransfer() error

AxelarGatewayDestination

import "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayDestination.sol";

Implementation of an ERC-7786 gateway destination adapter for the Axelar Network in dual mode.

The contract implements AxelarExecutable’s _execute function to execute the message, converting Axelar’s native workflow into the standard ERC-7786.

Functions
  • _execute(commandId, axelarSourceChain, axelarSourceAddress, adapterPayload)

AxelarExecutable
  • execute(commandId, sourceChain, sourceAddress, payload)

  • gateway()

AxelarGatewayBase
  • getEquivalentChain(input)

  • getRemoteGateway(caip2)

  • registerChainEquivalence(caip2, axelarSupported)

  • registerRemoteGateway(caip2, remoteGateway)

Ownable
  • owner()

  • _checkOwner()

  • renounceOwnership()

  • transferOwnership(newOwner)

  • _transferOwnership(newOwner)

Events
AxelarGatewayBase
  • RegisteredRemoteGateway(caip2, gatewayAddress)

  • RegisteredChainEquivalence(caip2, destinationChain)

Ownable
  • OwnershipTransferred(previousOwner, newOwner)

Errors
  • InvalidOriginGateway(sourceChain, axelarSourceAddress)

  • ReceiverExecutionFailed()

IAxelarExecutable
  • InvalidAddress()

  • NotApprovedByGateway()

AxelarGatewayBase
  • UnsupportedChain(caip2)

  • ChainEquivalenceAlreadyRegistered(caip2)

  • RemoteGatewayAlreadyRegistered(caip2)

Ownable
  • OwnableUnauthorizedAccount(account)

  • OwnableInvalidOwner(owner)

_execute(bytes32 commandId, string axelarSourceChain, string axelarSourceAddress, bytes adapterPayload) internal

Execution of a cross-chain message.

In this function:

  • axelarSourceChain is in the Axelar format. It should not be expected to be a proper CAIP-2 format

  • axelarSourceAddress is the sender of the Axelar message. That should be the remote gateway on the chain which the message originates from. It is NOT the sender of the ERC-7786 crosschain message.

Proper CAIP-10 encoding of the message sender (including the CAIP-2 name of the origin chain can be found in the message)

InvalidOriginGateway(string sourceChain, string axelarSourceAddress) error

ReceiverExecutionFailed() error

AxelarGatewayDuplex

import "@openzeppelin/community-contracts/crosschain/axelar/AxelarGatewayDuplex.sol";

A contract that combines the functionality of both the source and destination gateway adapters for the Axelar Network. Allowing to either send or receive messages across chains.

Functions
  • constructor(gateway, initialOwner)

AxelarGatewayDestination
  • _execute(commandId, axelarSourceChain, axelarSourceAddress, adapterPayload)

AxelarExecutable
  • execute(commandId, sourceChain, sourceAddress, payload)

  • gateway()

AxelarGatewaySource
  • supportsAttribute()

  • sendMessage(destinationChain, receiver, payload, attributes)

AxelarGatewayBase
  • getEquivalentChain(input)

  • getRemoteGateway(caip2)

  • registerChainEquivalence(caip2, axelarSupported)

  • registerRemoteGateway(caip2, remoteGateway)

Ownable
  • owner()

  • _checkOwner()

  • renounceOwnership()

  • transferOwnership(newOwner)

  • _transferOwnership(newOwner)

Events
AxelarGatewayBase
  • RegisteredRemoteGateway(caip2, gatewayAddress)

  • RegisteredChainEquivalence(caip2, destinationChain)

Ownable
  • OwnershipTransferred(previousOwner, newOwner)

IERC7786GatewaySource
  • MessagePosted(outboxId, sender, receiver, payload, attributes)

Errors
AxelarGatewayDestination
  • InvalidOriginGateway(sourceChain, axelarSourceAddress)

  • ReceiverExecutionFailed()

IAxelarExecutable
  • InvalidAddress()

  • NotApprovedByGateway()

AxelarGatewaySource
  • UnsupportedNativeTransfer()

AxelarGatewayBase
  • UnsupportedChain(caip2)

  • ChainEquivalenceAlreadyRegistered(caip2)

  • RemoteGatewayAlreadyRegistered(caip2)

Ownable
  • OwnableUnauthorizedAccount(account)

  • OwnableInvalidOwner(owner)

IERC7786GatewaySource
  • UnsupportedAttribute(selector)

constructor(contract IAxelarGateway gateway, address initialOwner) public

Initializes the contract with the Axelar gateway and the initial owner.