-
Notifications
You must be signed in to change notification settings - Fork 479
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 ERC: Cross-Chain Messaging Gateway #673
base: master
Are you sure you want to change the base?
Changes from all commits
9cc03cc
b932584
ed21209
e74c9e5
27c6cdb
91841f1
d6094bc
2f2f25b
97c02ee
e5aa1d3
b141e44
5c689bc
d0c00c8
d36ca6b
3f9b63b
195f596
0c8ecf5
2849377
9cb1a8a
eb3cf91
30eba48
8c68d86
81b9569
c44d88e
a333d23
2f221a0
cfc0b65
0b3c063
a9f313c
5cd3592
3d3c0c7
07934da
35d7ebb
67cc254
b84079a
f297a37
5f72c7d
4ece363
6918714
6953747
2ba7cb1
0d14e9f
3501274
63b0084
f7976e4
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,184 @@ | ||
--- | ||
eip: 7786 | ||
title: Cross-Chain Messaging Gateway | ||
description: An interface for contracts to send and receive cross-chain messages. | ||
author: Francisco Giordano (@frangio), Hadrien Croubois (@Amxx), Ernesto Garcia (@ernestognw), CJ Cobb (@cjcobb23) | ||
discussions-to: https://ethereum-magicians.org/t/erc-7786-cross-chain-messaging-gateway/21374 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2024-10-14 | ||
--- | ||
|
||
## Abstract | ||
|
||
This proposal describes an interface, and the corresponding workflow, for smart contracts to send arbitrary data through cross-chain messaging protocols. The end goal of this proposal is to have all such messaging protocols accessible via this interface (natively or using "adapters") to improve their composability and interoperability. That would allow a new class of cross-chain native smart contracts to emerge while reducing vendor lock-in. This proposal is modular by design, allowing users to leverage bridge-specific features through attributes while providing simple "universal" access to the simple feature of "just getting a simple message through". | ||
|
||
## Motivation | ||
|
||
Cross-chain messaging protocols (or bridges) allow communication between smart contracts deployed on different blockchains. There is a large diversity of such protocols with multiple degrees of decentralization, different architectures, implementing different interfaces, and providing different guarantees to users. | ||
|
||
Because almost every protocol implements a different workflow using a specific interface, portability between bridges is currently basically impossible. This also prevents the development of generic contracts that rely on cross chain communication. | ||
|
||
The objective of the ERC is to provide a standard interface, and a corresponding workflow, for performing cross-chain communication between contracts. Existing cross-chain communication protocols that do not natively implement this interface should be able to adopt it using adapter gateway contracts. | ||
|
||
Compared to previous ERCs in this area, this ERC offers compatibility with chains outside of the Ethereum/EVM ecosystem, and it is extensible to support the different feature sets of various protocols while offering a shared core of standard functionality. | ||
|
||
## Specification | ||
|
||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. | ||
|
||
### Message Field Encoding | ||
|
||
A cross-chain message consists of a sender, receiver, payload, and list of attributes. | ||
|
||
#### Sender & Receiver | ||
|
||
The sender account (in the source chain) and receiver account (in the destination chain) MUST be represented using CAIP-10 account identifiers. Note that these are ASCII-encoded strings. | ||
|
||
A CAIP-10 account identifier embeds a CAIP-2 chain identifier along with an address. In some parts of the interface, the address and the chain parts will be provided separately rather than as a single string, or the chain part will be implicit. | ||
|
||
#### Payload | ||
|
||
The payload is an opaque `bytes` value. | ||
|
||
#### Attributes | ||
|
||
Attributes are structured pieces of message data and/or metadata. Each attribute is a key-value pair, where the key determines the type and encoding of the value, as well as its meaning and behavior. | ||
|
||
Some attributes are message data that must be sent to the receiver, although they can be transformed as long as their meaning is preserved. Other attributes are metadata that will be used by the intervening gateways and potentially removed before the message reaches the receiver. | ||
|
||
The set of attributes is extensible. It is RECOMMENDED to standardize attributes and their characteristics by publishing them as ERCs. | ||
|
||
A gateway MAY support any set of attributes. An empty attribute list MUST always be accepted by a gateway. | ||
|
||
Each attribute key MUST have the format of a Solidity function signature, i.e., a name followed by a list of types in parentheses. For example, `minGasLimit(uint256)`. | ||
|
||
In this specification attributes are encoded as an array of `bytes` (i.e., `bytes[]`). Each element of the array MUST encode an attribute in the form of a Solidity function call, i.e., the first 4 bytes of the hash of the key followed by the ABI-encoded value. | ||
|
||
### Sending Procedure | ||
|
||
An **Source Gateway** is a contract that offers a protocol to send a message to a receiver on another chain. It MUST implement `IERC7786GatewaySource`. | ||
|
||
```solidity | ||
interface IERC7786GatewaySource { | ||
event MessagePosted(bytes32 indexed outboxId, string sender, string receiver, bytes payload, uint256 value, bytes[] attributes); | ||
|
||
error UnsupportedAttribute(bytes4 selector); | ||
|
||
function supportsAttribute(bytes4 selector) external view returns (bool); | ||
|
||
function sendMessage( | ||
string calldata destinationChain, // CAIP-2 chain identifier | ||
string calldata receiver, // CAIP-10 account address | ||
bytes calldata payload, | ||
bytes[] calldata attributes | ||
) external payable returns (bytes32 outboxId); | ||
} | ||
``` | ||
|
||
#### `supportsAttribute` | ||
|
||
Returns a boolean indicating whether an attribute is supported by the gateway, identified by the selector computed from the attribute signature. | ||
|
||
A gateway MAY be upgraded with support for additional attributes. Once present support for an attribute SHOULD NOT be removed to preserve backwards compatibility with users of the gateway. | ||
|
||
#### `sendMessage` | ||
|
||
Initiates the sending of a message. | ||
|
||
Further action MAY be required by the gateway to make the sending of the message effective, such as providing payment for gas. See Post-processing. | ||
|
||
MUST revert with `UnsupportedAttribute` if an unsupported attribute key is included. MAY revert if the value of an attribute is not a valid encoding for its expected type. | ||
|
||
MAY accept call value (native token) to be sent with the message. MUST revert if call value is included but it is not a feature supported by the gateway. It is unspecified how this value is represented on the destination. | ||
|
||
MAY generate and return a unique non-zero _outbox identifier_, otherwise returning zero. This identifier can be used to track the lifecycle of the message in the outbox in events and for post-processing. | ||
|
||
MUST emit a `MessagePosted` event, including the optional outbox identifier that is returned by the function. | ||
|
||
#### `MessagePosted` | ||
|
||
This event signals that a would-be sender has requested a message to be sent. | ||
|
||
If `outboxId` is present, post-processing MAY be required to send the message through the cross-chain channel. | ||
|
||
#### Post-processing | ||
|
||
After a sender has invoked `sendMessage`, further action MAY be required by the gateways to make the message effective. This is called _post-processing_. For example, some payment is typically required to cover the gas of executing the message at the destination. | ||
|
||
The exact interface for any such action is out of scope of this ERC. If the `postProcessingOwner` attribute is supported and present, such actions MUST be restricted to the specified account, otherwise they MUST be able to be performed by any party in a way that MUST NOT be able to compromise the eventual receipt of the message. | ||
|
||
### Reception Procedure | ||
|
||
A **Destination Gateway** is a contract that implements a protocol to validate messages sent on other chains. The interface of the destination gateway and how it is invoked is out of scope of this ERC. | ||
|
||
The protocol MUST ensure delivery of a sent message to its **receiver** using the `IERC7786Receiver` interface (specified below), which the receiver MUST implement. | ||
|
||
Once the message can be safely delivered (see Properties), the gateway MUST invoke `executeMessage` with the message contents. | ||
|
||
The gateway MUST verify that `executeMessage` returns the correct value, and MUST revert otherwise. | ||
|
||
```solidity | ||
interface IERC7786Receiver { | ||
function executeMessage( | ||
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
string calldata sourceChain, // CAIP-2 chain identifier | ||
string calldata sender, // CAIP-10 account address | ||
bytes calldata payload, | ||
bytes[] calldata attributes | ||
) external payable returns (bytes4); | ||
} | ||
``` | ||
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#### `executeMessage` | ||
|
||
Delivery of a message sent from another chain. | ||
|
||
The receiver MUST validate that the caller of this function is a **known gateway**, i.e., one whose underlying cross-chain messaging protocol it trusts. | ||
|
||
MUST return `IERC7786Receiver.executeMessage.selector` (`0x675b049b`). | ||
|
||
#### Interaction Diagram | ||
|
||
![](../assets/eip-7786/send-execute.svg) | ||
|
||
### Properties | ||
|
||
The protocol underlying a pair of gateways is expected to guarantee a series of properties. For detailed definition and discussion we refer to XChain Research’s _Cross-chain Interoperability Report_. | ||
|
||
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- The protocol MUST guarantee Safety: A message is delivered at the destination if and only if it was sent at the source. The delivery process must ensure a message is only delivered once the sending transaction is finalized, and not delivered more than once. Note that there can be multiple messages with identical parameters that must be delivered separately. | ||
- The protocol MUST guarantee Liveness: A sent message is delivered at the destination eventually, assuming Liveness and censorship-resistance of the source and destination chains. | ||
- The protocol SHOULD guarantee Timeliness: A sent message is delivered at the destination within a bounded delivery time, which should be documented. | ||
- The above properties SHOULD NOT rely on trust in some centralized actor. For example, safety should be guaranteed by some trustless mechanism such as a light client proof, or attestations by an open, decentralized validator set. Relaying should be decentralized or permissionless to ensure liveness; a centralized relayer can fail and thus halt the protocol. | ||
|
||
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
Amxx marked this conversation as resolved.
Show resolved
Hide resolved
|
||
### Pending discussion | ||
|
||
- Should the destination and receiver inputs of `sendMessage` be kept as two separate strings, or merged as a single CAIP-10 string with a `:` separator? This has implication of the calldata length, which in some cases may be stored. | ||
- Do we want the gateway to have the ability to inform users of the address of the new version, similar to how `AccessManager` can update then authority trusted by an `AccessManaged`? This could be useful if a gateway is ever deprecated in favor of a new version. | ||
- Should data and metadata attributes be split in two? What are data attributes used for? Do we need them? | ||
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. I would think that in the ERC-20 use case, it would be metadata, the gateway would look at it and either transfer the ERC-20 before calling the receiver or (arguably better), set an allowance to allow the destination to transfer the tokens to itself. In this case the metadata can be stripped, or passed on to the receiver. (It stripped, might require the receiver to encode it in its own data format in some cases. In other cases, it's not needed (e.g. buying an NFT whose price is fixed — in that case it will try to transfer the requested amount and either succeed or fail). Data on the other hand, seems unnecessary, since the sender already receives a payload it can use to encode whatever it needs. If it's useless to the gateways, it should be in the payload. 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. Btw, the ERC-20 use case is a nice illustration of the usefulness of metadata . A single-destination messaging system will really struggle to transfer ERC-20 and do a contract call at once (it would require something like making sure the ERC-20 contract itself be able to forward arbitrary calls to contracts). Now, for that use case, a possibly simpler solution would be to enable multicalls in the messaging interface. This needs to be at the gateway level because simply deploying a "multicall receiver" would not work: the caller of the ERC-20 contract to mint a token would be the multicall receiver instead of the gateway. I think it would be great to list off more potential use cases for metadata properties, but it seems potentially useful enough (for things we may not even foresee) that I would definitely keep it. I think the multicall system is probably very generally useful as well, and you may want to consider including it. EIP-4337 (in which strangely I see many parallels to this despite their very different nature) has a similar capability as well. 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.
I like this formulation! I actually think it's kind of implied by the fact that gateways have to support the attributes you're including, otherwise they'll reject the message. Regarding multicalls, I'd reframe it as "atomic multi-messages" or something like that. I'm a bit reluctant given that most protocols I've seen don't support this (I only recall LayerZero having this). Additionally it could technically be implemented as an attribute. Definitely something to consider though. |
||
- Passing full payload or payload hash (as done by Axelar) ? Same question for attributes, possibly different answer depending on attribute malleability. | ||
|
||
## Rationale | ||
|
||
Attributes are designed so that gateways can expose any specific features the bridge offers without having to use a specific endpoint. Having a unique endpoint, with modularity through attributes, SHOULD allow contracts to change the gateway they use while continuing to express messages the same way. This portability offers many advantages: | ||
|
||
- A contract that relies on a specific gateway for sending messages is vulnerable to the gateway being paused, deprecated, or simply breaking. If the communication between the contract and the gateway is standard, an admin of the contract COULD update the address (in storage) of the gateway to use. In particular, senders to update to the new gateway when a new version is available. | ||
- Bridge layering SHOULD be possible. In particular, this interface should allow for a new class of bridges that routes the message through multiple independent bridges. Delivery of the message could require one or multiple of these independent bridges depending on whether improved liveness or safety is desired. | ||
|
||
As some cross-chain communication protocols require additional parameters beyond the destination and the payload, and because we want to send messages through those bridges without any knowledge of these additional parameters, a post-processing of the message MAY be required (after `sendMessage` is called, and before the message is delivered). The additional parameters MAY be supported through attributes, which would remove the need for a post-processing step. If these additional parameters are not provided through an attribute, an additional call to the gateway is REQUIRED for the message to be sent. If possible, the gateway SHOULD be designed so that anyone with an incentive for the message to be delivered can jump in. A malicious actor providing invalid parameters SHOULD NOT prevent the message from being successfully relayed by someone else. | ||
|
||
Some protocols gateway support doing arbitrary direct calls on the receiver. In that case, the receiver must detect that they are being called by the gateway to properly identify cross-chain messages. Getters are available on the gateway to figure out where the cross-chain message comes from (source chain and sender address). This approach has the downside that it allows anyone to trigger any call from the gateway to any contract. This is dangerous if the gateway ever holds any assets ([ERC-20](./eip-20.md) or similar). The use of a dedicated `executeMessage` function on the receiver protects any assets or permissions held by the gateway against such attacks. If the ability to perform direct calls is desired, this can be implemented as a wrapper on top of any gateway that implements this ERC. | ||
|
||
## Backwards Compatibility | ||
|
||
Existing cross-chain messaging protocols implement proprietary interfaces. We recommend that protocols natively implement the standard interface defined here, and propose the development of standard adapters for those that don't. | ||
|
||
## Security Considerations | ||
|
||
Unfortunately, CAIP-2 and CAIP-10 names are not unique. Using non-canonical strings may lead to undefined behavior, including message delivery failure and locked assets. While source gateways have a role to play in checking that user input are valid, we also believe that more effort should be put into standardizing and documenting what the canonical format is for each CAIP-2 namespace. This effort is beyond the scope of this ERC. | ||
|
||
Needs discussion. | ||
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 add a note about replayability it, instructing that nonce management is an app-level concern. 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 sure I see the potential attack vector. The application isn't handling any signatures or transactions manually. The underlying protocols should ensure non-replayability. 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. Yeah but if they don't it's a security concern: e.g. minting multiple times. |
||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
sequenceDiagram | ||
box Source chain | ||
participant Sender | ||
participant SourceGateway | ||
end | ||
box Destination chain | ||
participant DestinationGateway | ||
participant Receiver | ||
end | ||
Sender->>SourceGateway: sendMessage(...) | ||
SourceGateway-->>DestinationGateway: [underlying protocol] | ||
DestinationGateway->>+Receiver: executeMessage(...) | ||
Receiver->>-Receiver: _processMessage(...) |
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.
There have been quite a few standards of these nature proposed, and none of them have seemingly achieved any traction.
Here is an overview of the state of these standards: https://github.com/0xFableOrg/xchain/blob/master/README.md#messaging-formats--interfaces
On the ERC front only, we have:
Do we need another one? What makes this one different / necessary? And most importantly, though I'm not sure that's in scope for the EIP motivation section: what will make it so that this one gets actually used?
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.
Thanks for the feedback! We should definitely address these points in the ERC. My views are:
ERC-7533 is very low level and seems to mandate a lot of details about the protocol. The goal of this new ERC is to be a viable interface for any underlying cross-chain messaging protocol.
ERC-5164's main drawback is lack of support for non-EVM chains, since it relies on the EVM's chain id. ERC-6170 technically supports any chain id format but doesn't specify which one, so it doesn't achieve portability. This new ERC mandates the use of CAIP-2 and CAIP-10 identifiers.
ERC-5164 also lacks the ability to expose other features/parameters of the underlying protocol such as setting a minimum gas limit and attaching tokens. ERC-6170 has a separate "bytes data" argument that could technically be used for these things but does not specify a format or way to query whether they're supported, so it would struggle with portability as is. This new ERC has an extensible mechanism for attributes that can expose more advanced bridge features, with a viable path to standardizing the different kinds of attributes.
The theory is that if the interface is simple and unopinionated yet expressive enough, it should be a no-brainer to adopt for the purpose of increasing interoperability and composability. That said in this space I think ecosystem coordination is what will make a standardized interface succeed. We're working with Axelar and actively reaching out to developers of other cross-chain messaging protocols to get feedback and a critical mass of interest and adoption.
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.
@norswap I'd be interested to hear your thoughts on the spec!
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.
In addition to what @frangio said, something else I would like to add is that neither ERC 5164 nor ERC 6170 standardize the interface that apps use to verify messages with the gateway/interop protocol. Which is a major component of any cross chain app, and without standardizing that layer, it is impossible to build a generic cross chain app, since the app is still tightly coupled with how messages are verified.
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.
@frangio Thanks for the answer, that all makes sense.
@cjcobb23 I'm not sure I fully understand — EIP6170 has a
receiveMessage
. The difference seems to be that theirs live in their inbox (gateway), which then will call the app (as presumably the calldata is a message to the app). If I understand correctly, that's the same thing as the "active" mode in this EIP (with the difference is that the gateway function is unspecified and calls thereceiveMessage
on the destination contract instead of another function of the app's choosing).While the passive mode is interesting, I don't think it really enables more use cases? The passive mode allows you to abstract the gateway (but they still need to be verified). This can equivalently be done in EIP6170 by having their inbox
receiveMessage
call a function in the app that checks themsg.sender
(who then similarly checks against a list of known inboxes).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.
yes I was talking about passive mode. But even in active mode, does EIP 6170 standardize the interface between the gateway and the dApp the message is sent to? What interface must the dApp implement to receive cross chain messages? Is the
message_
field just calldata, and is the original sender and source chain propagated to the dApp and if so how? I think these things are all important to spell out.