Skip to content
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

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
9cc03cc
adding draft
Amxx Oct 14, 2024
b932584
Add link to discussion thread
Amxx Oct 14, 2024
ed21209
last version
Amxx Oct 14, 2024
e74c9e5
Merge remote-tracking branch 'amxx/new-erc/crosschain-gateway-interfa…
Amxx Oct 14, 2024
27c6cdb
Update ERCS/erc-yyyy.md
Amxx Oct 16, 2024
91841f1
Update ERCS/erc-yyyy.md
Amxx Oct 16, 2024
d6094bc
rename ERC file and interfaces
Amxx Oct 16, 2024
2f2f25b
add erc link
Amxx Oct 16, 2024
97c02ee
Update erc-7786.md
Amxx Oct 17, 2024
e5aa1d3
Apply suggestions from code review
Amxx Oct 22, 2024
b141e44
Apply suggestions from code review
Amxx Oct 22, 2024
5c689bc
Update erc-7786.md
Amxx Oct 22, 2024
d0c00c8
Update ERCS/erc-7786.md
Amxx Oct 22, 2024
d36ca6b
rename source and destination to sourceChain and destinationChain
Amxx Oct 29, 2024
3f9b63b
rename validateReceivedMessage to setMessageExecuted
Amxx Oct 29, 2024
195f596
Update erc-7786.md
Amxx Oct 29, 2024
0c8ecf5
Update ERCS/erc-7786.md
Amxx Oct 29, 2024
2849377
simplify events
frangio Oct 31, 2024
9cb1a8a
clarify only-once safety
frangio Oct 31, 2024
eb3cf91
edit abstract motivation
frangio Oct 31, 2024
30eba48
clarify receiver/dest gateway
frangio Oct 31, 2024
8c68d86
reword
frangio Nov 1, 2024
81b9569
Merge pull request #1 from frangio/new-erc/crosschain-gateway-interface
Amxx Nov 1, 2024
c44d88e
Update ERCS/erc-7786.md
Amxx Nov 1, 2024
a333d23
Apply suggestions from code review
Amxx Nov 5, 2024
2f221a0
executeMessage returns bytes4
Amxx Nov 5, 2024
cfc0b65
add diagrams
frangio Nov 5, 2024
0b3c063
Apply suggestions from code review
Amxx Nov 5, 2024
a9f313c
add _processMessage
frangio Nov 5, 2024
5cd3592
use images
frangio Nov 5, 2024
3d3c0c7
fix images
frangio Nov 5, 2024
07934da
Merge branch 'new-erc/crosschain-gateway-interface' into new-erc/cros…
Amxx Nov 5, 2024
35d7ebb
Merge pull request #2 from frangio/new-erc/crosschain-gateway-interface
Amxx Nov 5, 2024
67cc254
Removing link
Amxx Nov 5, 2024
b84079a
Update erc-7786.md
Amxx Nov 5, 2024
f297a37
Update ERCS/erc-7786.md
Amxx Nov 20, 2024
5f72c7d
Remove passive mode
ernestognw Nov 28, 2024
4ece363
Update ERCS/erc-7786.md
ernestognw Nov 28, 2024
6918714
Merge pull request #3 from ernestognw/new-erc/crosschain-gateway-inte…
Amxx Nov 28, 2024
6953747
Update erc-7786.md
Amxx Nov 28, 2024
2ba7cb1
remove passive mode
frangio Nov 28, 2024
0d14e9f
remove old paragraph
frangio Nov 28, 2024
3501274
merge
frangio Nov 28, 2024
63b0084
Merge pull request #4 from frangio/new-erc/crosschain-gateway-interface
Amxx Nov 28, 2024
f7976e4
Update ERCS/erc-7786.md
Amxx Nov 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions ERCS/erc-7786.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
---
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.

Copy link

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?

Copy link
Contributor

@frangio frangio Oct 27, 2024

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.

what will make it so that this one gets actually used?

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.

Copy link
Contributor

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!

Copy link

@cjcobb23 cjcobb23 Oct 30, 2024

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.

Copy link

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 the receiveMessage 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 the msg.sender (who then similarly checks against a list of known inboxes).

Copy link

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.

## 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 signature);

function supportsAttribute(bytes4 signature) external view returns (bool);
Amxx marked this conversation as resolved.
Show resolved Hide resolved

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

The underlying protocol MUST ensure delivery of the message to the **receiver**, which MUST implement `IERC7786Receiver`. The requirements for `executeMessage` will be detailed further below. Upon successful processing of the message, the receiver MUST return `IERC7786Receiver.executeMessage.selector` (`0xc887c5da`).

```solidity
interface IERC7786Receiver {
function executeMessage(
Amxx marked this conversation as resolved.
Show resolved Hide resolved
address gateway,
bytes calldata gatewayMessageKey,
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

A **Destination Gateway** is a contract that implements a protocol to validate messages sent on other chains. The gateway can operate in Active or Passive Mode, depending on whether `executeMessage` is invoked by the gateway itself or some other acocunt.

#### Active Mode

The gateway directly invokes `executeMessage`, and only does so with valid messages. The receiver MUST assume that a message is valid if the caller is a known gateway.

The arguments `gateway` and `gatewayMessageKey` are unused in active mode and SHOULD be zero and empty respectively.
Amxx marked this conversation as resolved.
Show resolved Hide resolved

The gateway MUST verify that `executeMessage` returns the correct value, and MUST revert if that is not the case.

##### Interaction Diagram

![](../assets/erc-7786/active-mode.svg)

#### Passive Mode
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the active / passive distinction, and don't really understand the passive mode's use case (cf. discussion on the comment thread in the motivation section above).

At first reading, I understood it as a way to distinguish between "permissioned" calls from a gateway operator, and "permissionless" calls for systems where proving can be done without permissionning things (light clients, zk). That doesn't seem to be the case, and even if it were, it could be achieve by letting people permissionlessly call a function on the gateway that then calls receiveMessage.

But the actual behaviour is ... not clear. The description makes it sound like it's validation only. This is a fair use case: a relayer may want to check if a message would succeed on the destination before relaying it. But can be achieved by either (1) an eth_call, even in permissioned cases (spoof the authorized sender, though this is a bit ugly/brittle and leaks implementation details), (2) a verifyMessage function (meant to be eth_called only) that verifies the non-permissioned parts (authenticity checks if any and app execution).

But maybe that's not what it does at all, as setMessageExecuted below seems to imply this is more than verification but actually stores an unexecuted message for later execution. This only seems useful insofar that the system is permissioned and the operator can eschew retrieving the source message from the source and only perform verification on it. But in a permissioned system, verification will require looking at the source anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passive mode comes from the observation that some protocols avoid making calls from their gateway for security reasons. The one we know of is Axelar, and I had the impression that Wormhole worked like this too, but I think I misread the docs and it actually works in active mode (...mostly, they actually have something like "multi-message delivery" where only the main message is "actively" validated, and the other bundled messages have to be validated in a "passive-like" workflow).

We're looking at the possibility of removing passive mode to simplify the standard.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with removing passive mode from the standard, to keep things simple


The gateway does not directly invoke `executeMessage`, but provides a means to validate messages. The receiver allows any party to invoke `executeMessage`, but if the caller is not a known gateway it MUST check that the gateway provided as an argument is a known gateway, and it MUST validate the message against it before accepting it, forwarding the message key.

A gateway acting in passive mode MUST implement `IERC7786GatewayDestinationPassive`. If a gateway operates exclusively in active mode, the implementation of this interface is OPTIONAL.

```solidity
interface IERC7786GatewayDestinationPassive {
function setMessageExecuted(
bytes calldata messageKey,
string calldata sourceChain, // CAIP-2 chain identifier
string calldata sender, // CAIP-10 account address
bytes calldata payload,
bytes[] calldata attributes
) external;
}
```

##### `setMessageExecuted`
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super confusing.

  • It implies (but this is never stated explicitly) that messages have to be stored somewhere prior to this being called. Presumably by a previous call to receiveMessage?
    - This is super wasteful in terms of chain storage, and is expensive as well.
  • I'm not entirely sure what the expected rationale is... a "gateway operator" wait for someone to call receiveMessage then actually executes it and calls setMessageExecuted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are messages usually relayed/executed ?

There are cases such as mainnet->matic were the execution is part of the protocol, but in most cases, the execution involves some kind of ticket being passed and stored between chains.

For matic -> mainnet, we have a state root that is used to prove stuff that happened on matic. In that case the messageKey could be a merkle inclusion proof of some event in this state.

AFAIK, Arbitrum has a ticket system, which is basically the storage we need here.

So yes its "wastefull", but unless the relayer has some specific authentication, it feels like its needed, and we already ahve this.


Now I get the possible confusion with the fact that the passive mode is optional, and only needs to be supported if the active mode has some failure mode. My personal opinion is that the passive mode can be hidden behind an "active adaptor". Many protocole already have a "retry mechanism" in the gateway. This "active adaptor" would turn a passive gateway into an active one with a similar "retry mechanism".

The reason we have this passive mode is that some protocole do work that way, and AFAIK they don't want to implement/maintain this active adaptor themselves. We could technically get rid of passive mode, and require someone to maintain that active adaptor ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this passive mode is matching Axelar's workflow

"Someone/anyone" calls the destination contract with message details. This could use any endpoint, though there is a "standard" one that the axelar relayer networks uses, and that receiver that want use this network must have.

The receiver then calls axelar to confirm the details are correct. Axelar just says "yes or no". The receiver can fail, or do whatever they want.

Again the rational here is that the axelar gateway does never call any contract directly (for safety / reentrenacy protection)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That probably doesn't need to be enshrined in the interface I think.

The ticketing system can be implementation-specific, a detail that only the gateway knows about. Then someone (whether the gateway in active mode or the user in passive mode) needs to call receiveMessage with the details (making it effectively similar to what setMessageExecuted currently does).

Copy link
Contributor

@frangio frangio Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ticketing system can be implementation-specific, a detail that only the gateway knows about. Then someone (whether the gateway in active mode or the user in passive mode) needs to call receiveMessage with the details

Unless I'm misunderstanding this is exactly what the current spec says.

setMessageExecuted (which was at some point called validateReceivedMessage) is needed for when the message is submitted via receiveMessage by an account that isn't the gateway, so the message needs to be validated with the gateway before the receiver accepts it.

Perhaps a couple of diagrams for the function calls that happen in active and passive mode would help make this clearer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some diagrams.


Checks that there is a valid and as yet unexecuted message whose contents are exactly those passed as arguments and whose receiver is the caller of the function. The message key MAY be an identifier, or another piece of data necessary for validation.

MUST revert if the message is invalid or has already been executed.

##### Interaction Diagram

![](../assets/erc-7786/passive-mode.svg)

Amxx marked this conversation as resolved.
Show resolved Hide resolved
#### Dual Active-Passive Mode

A gateway MAY operate in both active and passive modes, or it MAY switch from operating exclusively in active mode to passive mode or vice versa.

A receiver SHOULD support both active and passive modes for any gateway. This is accomplished by first checking whether the caller of `executeMessage` is a known gateway, and only validating the message if it is not; the first case supports an active mode gateway, while the second case supports a passive mode gateway.

### 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*.

- 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?
Copy link

Choose a reason for hiding this comment

The 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.

Copy link

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's useless to the gateways, it should be in the payload.

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](./erc-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.
Copy link

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link

Choose a reason for hiding this comment

The 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).
13 changes: 13 additions & 0 deletions assets/erc-7786/active-mode.mermaid
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(...)
Loading
Loading