-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add documentation for crosschain message passing #31
base: master
Are you sure you want to change the base?
Changes from all commits
0ac6bdb
886a498
e1426a1
9be5fff
1bfadfc
1f6058a
36e4de1
5074e7f
3e8620d
c7b4205
0d0e1d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
= Crosschain | ||
|
||
[.readme-notice] | ||
NOTE: 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, which defines the following interfaces: | ||
|
||
* {IERC7786GatewaySource}: A contract interface to send a message to another contract on a different chain. | ||
* {IERC7786Receiver}: An interface that allows an smart contract to receive a crosschain message provided by a trusted destination gateway. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't the gateway itself implement |
||
|
||
The library provides an implementation of an ERC-7786 receiver contract as a building block: | ||
|
||
* {ERC7786Receiver}: ERC-7786 cross-chain message receiver. | ||
|
||
Given ERC-7786 could be enabled natively or via adapters. Developers can access interoperability protocols through gateway adapters. The library includes the following gateway adapters: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not cohesive |
||
|
||
* {AxelarGatewayBase}: Core gateway logic for the https://www.axelar.network/[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 | ||
|
||
{{IERC7786GatewaySource}} | ||
|
||
== Clients | ||
|
||
{{IERC7786Receiver}} | ||
|
||
{{ERC7786Receiver}} | ||
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
== Adapters | ||
|
||
=== Axelar | ||
|
||
{{AxelarGatewayBase}} | ||
|
||
{{AxelarGatewaySource}} | ||
|
||
{{AxelarGatewayDestination}} | ||
|
||
{{AxelarGatewayDuplex}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
|
||
pragma solidity ^0.8.27; | ||
|
||
import {IERC7786Receiver} from "../../interfaces/IERC7786.sol"; | ||
import {IERC7786Receiver} from "./IERC7786.sol"; | ||
|
||
/** | ||
* @dev Base implementation of an ERC-7786 compliant cross-chain message receiver. | ||
|
@@ -33,7 +33,7 @@ abstract contract ERC7786Receiver is IERC7786Receiver { | |
} | ||
|
||
/// @dev Virtual getter that returns whether an address is a valid ERC-7786 gateway. | ||
function _isKnownGateway(address instance) internal view virtual returns (bool); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this change here? |
||
function _isKnownGateway(address instance) internal virtual returns (bool); | ||
|
||
/// @dev Virtual function that should contain the logic to execute when a cross-chain message is received. | ||
function _processMessage( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
Comment on lines
+1
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to do a |
||
|
||
/** | ||
* @dev Interface for ERC-7786 source gateways. | ||
* | ||
* See ERC-7786 for more details | ||
*/ | ||
interface IERC7786GatewaySource { | ||
/** | ||
* @dev Event emitted when a message is created. If `outboxId` is zero, no further processing is necessary. If | ||
* `outboxId` is not zero, then further (gateway specific, and non-standardized) action is required. | ||
*/ | ||
event MessagePosted( | ||
bytes32 indexed outboxId, | ||
string sender, // CAIP-10 account identifier (chain identifier + ":" + account address) | ||
string receiver, // CAIP-10 account identifier (chain identifier + ":" + account address) | ||
bytes payload, | ||
bytes[] attributes | ||
); | ||
|
||
/// @dev This error is thrown when a message creation fails because of an unsupported attribute being specified. | ||
error UnsupportedAttribute(bytes4 selector); | ||
|
||
/// @dev Getter to check whether an attribute is supported or not. | ||
function supportsAttribute(bytes4 selector) external view returns (bool); | ||
|
||
/** | ||
* @dev 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. | ||
* @param destinationChain {CAIP2} chain identifier | ||
* @param receiver {CAIP10} account address (does not include the chain identifier) | ||
* | ||
* * MUST emit a {MessagePosted} 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. | ||
*/ | ||
function sendMessage( | ||
string calldata destinationChain, | ||
string calldata receiver, | ||
bytes calldata payload, | ||
bytes[] calldata attributes | ||
) external payable returns (bytes32 outboxId); | ||
} | ||
|
||
/** | ||
* @dev Interface for the ERC-7786 client contract (receiver). | ||
* | ||
* See ERC-7786 for more details | ||
*/ | ||
interface IERC7786Receiver { | ||
/** | ||
* @dev Endpoint for receiving cross-chain message. | ||
* @param sourceChain {CAIP2} chain identifier | ||
* @param sender {CAIP10} account address (does not include the chain identifier) | ||
* | ||
* This function may be called directly by the gateway. | ||
*/ | ||
function executeMessage( | ||
string calldata sourceChain, // CAIP-2 chain identifier | ||
string calldata sender, // CAIP-10 account address (does not include the chain identifier) | ||
bytes calldata payload, | ||
bytes[] calldata attributes | ||
) external payable returns (bytes4); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// contracts/MyCustomAxelarGatewayDestination.sol | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import {AxelarGatewayDestination, AxelarExecutable} from "../../../crosschain/axelar/AxelarGatewayDestination.sol"; | ||
import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; | ||
|
||
abstract contract MyCustomAxelarGatewayDestination is AxelarGatewayDestination { | ||
/// @dev Initializes the contract with the Axelar gateway and the initial owner. | ||
constructor(IAxelarGateway gateway, address initialOwner) AxelarExecutable(address(gateway)) {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// contracts/MyCustomAxelarGatewayDuplex.sol | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import {AxelarGatewayDuplex, AxelarExecutable} from "../../../crosschain/axelar/AxelarGatewayDuplex.sol"; | ||
import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; | ||
|
||
abstract contract MyCustomAxelarGatewayDuplex is AxelarGatewayDuplex { | ||
/// @dev Initializes the contract with the Axelar gateway and the initial owner. | ||
constructor(IAxelarGateway gateway, address initialOwner) AxelarGatewayDuplex(gateway, initialOwner) {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// contracts/MyERC7786ReceiverContract.sol | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; | ||
import {AxelarGatewaySource} from "../../../crosschain/axelar/AxelarGatewaySource.sol"; | ||
import {AxelarGatewayBase} from "../../../crosschain/axelar/AxelarGatewayBase.sol"; | ||
import {IAxelarGateway} from "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol"; | ||
|
||
abstract contract MyCustomAxelarGatewaySource is AxelarGatewaySource { | ||
/// @dev Initializes the contract with the Axelar gateway and the initial owner. | ||
constructor(IAxelarGateway gateway, address initialOwner) Ownable(initialOwner) AxelarGatewayBase(gateway) {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// contracts/MyERC7786GatewaySource.sol | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
import {CAIP2} from "@openzeppelin/contracts/utils/CAIP2.sol"; | ||
import {CAIP10} from "@openzeppelin/contracts/utils/CAIP10.sol"; | ||
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; | ||
import {IERC7786GatewaySource} from "../../../interfaces/IERC7786.sol"; | ||
|
||
abstract contract MyERC7786GatewaySource is IERC7786GatewaySource { | ||
using Strings for address; | ||
|
||
error UnsupportedNativeTransfer(); | ||
|
||
/// @inheritdoc IERC7786GatewaySource | ||
function supportsAttribute(bytes4 /*selector*/) public pure returns (bool) { | ||
return false; | ||
} | ||
|
||
/// @inheritdoc IERC7786GatewaySource | ||
function sendMessage( | ||
string calldata destinationChain, // CAIP-2 chain identifier | ||
string calldata receiver, // CAIP-10 account address (does not include the chain identifier) | ||
bytes calldata payload, | ||
bytes[] calldata attributes | ||
) external payable returns (bytes32 outboxId) { | ||
require(msg.value == 0, UnsupportedNativeTransfer()); | ||
// Use of `if () revert` syntax to avoid accessing attributes[0] if it's empty | ||
if (attributes.length > 0) | ||
revert UnsupportedAttribute(attributes[0].length < 0x04 ? bytes4(0) : bytes4(attributes[0][0:4])); | ||
|
||
// Emit event | ||
outboxId = bytes32(0); // Explicitly set to 0. Can be used for post-processing | ||
emit MessagePosted( | ||
outboxId, | ||
CAIP10.format(CAIP2.local(), msg.sender.toChecksumHexString()), | ||
CAIP10.format(destinationChain, receiver), | ||
payload, | ||
attributes | ||
); | ||
|
||
// Optionally: If this is an adapter, send the message to a protocol gateway for processing | ||
// This may require the logic for tracking destination gateway addresses and chain identifiers | ||
|
||
return outboxId; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// contracts/MyERC7786ReceiverContract.sol | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.22; | ||
|
||
import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; | ||
import {ERC7786Receiver} from "../../../crosschain/utils/ERC7786Receiver.sol"; | ||
|
||
contract MyERC7786ReceiverContract is ERC7786Receiver, AccessManaged { | ||
constructor(address initialAuthority) AccessManaged(initialAuthority) {} | ||
|
||
/// @dev Check if the given instance is a known gateway. | ||
function _isKnownGateway(address /* instance */) internal virtual override restricted returns (bool) { | ||
// The restricted modifier ensures that this function is only called by a known authority. | ||
return true; | ||
} | ||
|
||
/// @dev Internal endpoint for receiving cross-chain message. | ||
/// @param sourceChain {CAIP2} chain identifier | ||
/// @param sender {CAIP10} account address (does not include the chain identifier) | ||
function _processMessage( | ||
address gateway, | ||
string calldata sourceChain, | ||
string calldata sender, | ||
bytes calldata payload, | ||
bytes[] calldata attributes | ||
) internal virtual override restricted { | ||
// Process the message here | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
* xref:index.adoc[Overview] | ||
* xref:account-abstraction.adoc[Account Abstraction] | ||
* xref:crosschain.adoc[Crosschain] | ||
* xref:utilities.adoc[Utilities] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth an href to ERC-7786?