Crosschain
This document is better viewed at https://docs.openzeppelin.com/community-contracts/api/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. -
ERC7786OpenBridge
: 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:
-
AxelarGatewayBase
: Core gateway logic for the Axelar adapter. -
AxelarGatewaySource
: ERC-7786 source gateway adapter (sending side) for Axelar. -
AxelarGatewayDestination
: ERC-7786 destination gateway adapter (receiving side) for Axelar. -
AxelarGatewayDuplex
: ERC-7786 gateway adapter that operates in both directions (i.e. send and receive messages) using the Axelar network.
Gateways
ERC7786OpenBridge
import "@openzeppelin/community-contracts/crosschain/ERC7786OpenBridge.sol";
N of M gateway: Sends your message through M independent gateways. It will be delivered to the receiver by an equivalent bridge on the destination chain if N of the M gateways agree.
-
constructor(owner_, gateways_, threshold_)
-
supportsAttribute()
-
sendMessage(recipient, payload, attributes)
-
receiveMessage(, sender, payload)
-
getGateways()
-
getThreshold()
-
getRemoteBridge(chain)
-
getRemoteBridge(chainType, chainReference)
-
addGateway(gateway)
-
removeGateway(gateway)
-
setThreshold(newThreshold)
-
registerRemoteBridge(bridge)
-
pause()
-
unpause()
-
sweep(to)
-
_addGateway(gateway)
-
_removeGateway(gateway)
-
_setThreshold(newThreshold)
-
_registerRemoteBridge(bridge)
-
paused()
-
_requireNotPaused()
-
_requirePaused()
-
_pause()
-
_unpause()
-
owner()
-
_checkOwner()
-
renounceOwnership()
-
transferOwnership(newOwner)
-
_transferOwnership(newOwner)
-
OutboxDetails(sendId, outbox)
-
Received(receiveId, gateway)
-
ExecutionSuccess(receiveId)
-
ExecutionFailed(receiveId)
-
GatewayAdded(gateway)
-
GatewayRemoved(gateway)
-
ThresholdUpdated(threshold)
-
RemoteRegistered(remote)
-
Paused(account)
-
Unpaused(account)
-
OwnershipTransferred(previousOwner, newOwner)
-
MessageSent(sendId, sender, receiver, payload, value, attributes)
-
UnsupportedNativeTransfer()
-
ERC7786OpenBridgeInvalidCrosschainSender()
-
ERC7786OpenBridgeAlreadyExecuted()
-
ERC7786OpenBridgeRemoteNotRegistered(chainType, chainReference)
-
ERC7786OpenBridgeGatewayAlreadyRegistered(gateway)
-
ERC7786OpenBridgeGatewayNotRegistered(gateway)
-
ERC7786OpenBridgeThresholdViolation()
-
ERC7786OpenBridgeInvalidExecutionReturnValue()
-
RemoteAlreadyRegistered(remote)
-
EnforcedPause()
-
ExpectedPause()
-
OwnableUnauthorizedAccount(account)
-
OwnableInvalidOwner(owner)
-
UnsupportedAttribute(selector)
sendMessage(bytes recipient, bytes payload, bytes[] attributes) → bytes32 sendId
public
Using memory instead of calldata avoids stack too deep errors
receiveMessage(bytes32, bytes sender, bytes payload) → bytes4
public
This function serves a dual purpose:
It will be called by ERC-7786 gateways with message coming from the the corresponding bridge 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 bridge 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 aExecutionFailed
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.
|
sweep(address payable to)
public
Recovery method in case value is ever received through receiveMessage
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 receiveMessage
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.
-
receiveMessage(receiveId, sender, payload)
-
_isKnownGateway(instance)
-
_processMessage(gateway, receiveId, sender, payload)
-
ERC7786ReceiverInvalidGateway(gateway)
-
ERC7786ReceivePassiveModeValue()
receiveMessage(bytes32 receiveId, bytes sender, bytes payload) → bytes4
public
Endpoint for receiving cross-chain message.
This function may be called directly by the gateway.
_isKnownGateway(address instance) → bool
internal
Virtual getter that returns whether an address is a valid ERC-7786 gateway.
Adapters
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. ERC-7930 chain type and reference to Axelar chain identifiers) and remote gateways (i.e. gateways on other chains) to facilitate cross-chain communication.
-
constructor(_gateway)
-
getAxelarChain(input)
-
getErc7930Chain(input)
-
getRemoteGateway(chain)
-
getRemoteGateway(chainType, chainReference)
-
registerChainEquivalence(chain, axelar)
-
registerRemoteGateway(remote)
-
owner()
-
_checkOwner()
-
renounceOwnership()
-
transferOwnership(newOwner)
-
_transferOwnership(newOwner)
-
RegisteredRemoteGateway(remote)
-
RegisteredChainEquivalence(erc7930binary, axelar)
-
OwnershipTransferred(previousOwner, newOwner)
-
UnsupportedERC7930Chain(erc7930binary)
-
UnsupportedAxelarChain(axelar)
-
InvalidChainIdentifier(erc7930binary)
-
ChainEquivalenceAlreadyRegistered(erc7930binary, axelar)
-
RemoteGatewayAlreadyRegistered(chainType, chainReference)
-
OwnableUnauthorizedAccount(account)
-
OwnableInvalidOwner(owner)
-
contract IAxelarGateway _axelarGateway
constructor(contract IAxelarGateway _gateway)
internal
Sets the local gateway address (i.e. Axelar’s official gateway for the current chain).
getAxelarChain(bytes input) → string output
public
Returns the equivalent chain given an id that can be either either a binary interoperable address or an Axelar network identifier.
getRemoteGateway(bytes chain) → bytes
public
Returns the address of the remote gateway for a given chainType and chainReference.
registerChainEquivalence(bytes chain, string axelar)
public
Registers a chain equivalence between a binary interoperable address an Axelar network identifier.
RegisteredChainEquivalence(bytes erc7930binary, string axelar)
event
A chain equivalence has been registered.
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.
-
supportsAttribute()
-
sendMessage(recipient, payload, attributes)
-
getAxelarChain(input)
-
getErc7930Chain(input)
-
getRemoteGateway(chain)
-
getRemoteGateway(chainType, chainReference)
-
registerChainEquivalence(chain, axelar)
-
registerRemoteGateway(remote)
-
owner()
-
_checkOwner()
-
renounceOwnership()
-
transferOwnership(newOwner)
-
_transferOwnership(newOwner)
-
RegisteredRemoteGateway(remote)
-
RegisteredChainEquivalence(erc7930binary, axelar)
-
OwnershipTransferred(previousOwner, newOwner)
-
MessageSent(sendId, sender, receiver, payload, value, attributes)
-
UnsupportedNativeTransfer()
-
UnsupportedERC7930Chain(erc7930binary)
-
UnsupportedAxelarChain(axelar)
-
InvalidChainIdentifier(erc7930binary)
-
ChainEquivalenceAlreadyRegistered(erc7930binary, axelar)
-
RemoteGatewayAlreadyRegistered(chainType, chainReference)
-
OwnableUnauthorizedAccount(account)
-
OwnableInvalidOwner(owner)
-
UnsupportedAttribute(selector)
sendMessage(bytes recipient, bytes payload, bytes[] attributes) → bytes32 sendId
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.
-
MUST emit a {MessageSent} event.
If any of the attributes
is not supported, this function SHOULD revert with an {UnsupportedAttribute} error.
Other errors SHOULD revert with errors not specified in ERC-7786.
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.
-
_execute(commandId, axelarSourceChain, axelarSourceAddress, adapterPayload)
-
execute(commandId, sourceChain, sourceAddress, payload)
-
gateway()
-
getAxelarChain(input)
-
getErc7930Chain(input)
-
getRemoteGateway(chain)
-
getRemoteGateway(chainType, chainReference)
-
registerChainEquivalence(chain, axelar)
-
registerRemoteGateway(remote)
-
owner()
-
_checkOwner()
-
renounceOwnership()
-
transferOwnership(newOwner)
-
_transferOwnership(newOwner)
-
RegisteredRemoteGateway(remote)
-
RegisteredChainEquivalence(erc7930binary, axelar)
-
OwnershipTransferred(previousOwner, newOwner)
-
InvalidOriginGateway(axelarSourceChain, axelarSourceAddress)
-
ReceiverExecutionFailed()
-
InvalidAddress()
-
NotApprovedByGateway()
-
UnsupportedERC7930Chain(erc7930binary)
-
UnsupportedAxelarChain(axelar)
-
InvalidChainIdentifier(erc7930binary)
-
ChainEquivalenceAlreadyRegistered(erc7930binary, axelar)
-
RemoteGatewayAlreadyRegistered(chainType, chainReference)
-
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 ERC-7930 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 ERC-7930 encoding of the crosschain message sender can be found in the message
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.
-
constructor(gateway, initialOwner)
-
_execute(commandId, axelarSourceChain, axelarSourceAddress, adapterPayload)
-
execute(commandId, sourceChain, sourceAddress, payload)
-
gateway()
-
supportsAttribute()
-
sendMessage(recipient, payload, attributes)
-
getAxelarChain(input)
-
getErc7930Chain(input)
-
getRemoteGateway(chain)
-
getRemoteGateway(chainType, chainReference)
-
registerChainEquivalence(chain, axelar)
-
registerRemoteGateway(remote)
-
owner()
-
_checkOwner()
-
renounceOwnership()
-
transferOwnership(newOwner)
-
_transferOwnership(newOwner)
-
RegisteredRemoteGateway(remote)
-
RegisteredChainEquivalence(erc7930binary, axelar)
-
OwnershipTransferred(previousOwner, newOwner)
-
MessageSent(sendId, sender, receiver, payload, value, attributes)
-
InvalidOriginGateway(axelarSourceChain, axelarSourceAddress)
-
ReceiverExecutionFailed()
-
InvalidAddress()
-
NotApprovedByGateway()
-
UnsupportedNativeTransfer()
-
UnsupportedERC7930Chain(erc7930binary)
-
UnsupportedAxelarChain(axelar)
-
InvalidChainIdentifier(erc7930binary)
-
ChainEquivalenceAlreadyRegistered(erc7930binary, axelar)
-
RemoteGatewayAlreadyRegistered(chainType, chainReference)
-
OwnableUnauthorizedAccount(account)
-
OwnableInvalidOwner(owner)
-
UnsupportedAttribute(selector)