Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7683: Cross Chain Intents

An interface for cross-chain trade execution systems.

Authors Mark Toda (@marktoda), Matt Rice (@mrice32), Nick Pai (@nicholaspai)
Created 2024-04-11
Discussion Link https://ethereum-magicians.org/t/erc-cross-chain-intents-standard/19619

Abstract

The following standard allows for the implementation of a standard API for cross-chain trade execution systems. This standard provides a generic CrossChainOrder struct, as well as a standard ISettlementContract smart contract interface.

Motivation

Intent-based systems have become the preeminent solution for end-user cross-chain interaction by abstracting away the complexity and time constraints of traditional bridges. One of the key difficulties for cross-chain intents systems is accessing sufficient liquidity and a network of active fillers across chains. This challenge may be exacerbated as the number of distinct chains increases over time. The end result of this is a poor experience for users including higher costs, longer wait times and higher failure rates than necessary.

By implementing a standard, cross-chain intents systems can interoperate and share infrastructure such as order dissemination services and filler networks, thereby improving end-user experience by increasing competition for fulfilling user intents.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

CrossChainOrder struct

A compliant cross-chain order type MUST be ABI decodable into the CrossChainOrder type.

/// @title CrossChainOrder type
/// @notice Standard order struct to be signed by swappers, disseminated to fillers, and submitted to settlement contracts
struct CrossChainOrder {
	/// @dev The contract address that the order is meant to be settled by.
	/// Fillers send this order to this contract address on the origin chain
	address settlementContract;
	/// @dev The address of the user who is initiating the swap,
	/// whose input tokens will be taken and escrowed
	address swapper;
	/// @dev Nonce to be used as replay protection for the order
	uint256 nonce;
	/// @dev The chainId of the origin chain
	uint32 originChainId;
	/// @dev The timestamp by which the order must be initiated
	uint32 initiateDeadline;
	/// @dev The timestamp by which the order must be filled on the destination chain
	uint32 fillDeadline;
	/// @dev Arbitrary implementation-specific data
	/// Can be used to define tokens, amounts, destination chains, fees, settlement parameters,
	/// or any other order-type specific information
	bytes orderData;
}

Cross-chain execution systems implementing this standard SHOULD create a custom sub-type that can be parsed from the arbitrary orderData field. This may include information such as the tokens involved in the swap, the destination chain IDs, fulfillment constraints or settlement oracles.

ResolvedCrossChainOrder struct

A compliant cross-chain order type MUST be convertible into the ResolvedCrossChainOrder struct.

/// @title ResolvedCrossChainOrder type
/// @notice An implementation-generic representation of an order
/// @dev Defines all requirements for filling an order by unbundling the implementation-specific orderData.
/// @dev Intended to improve integration generalization by allowing fillers to compute the exact input and output information of any order
struct ResolvedCrossChainOrder {
	/// @dev The contract address that the order is meant to be settled by.
	address settlementContract;
	/// @dev The address of the user who is initiating the swap
	address swapper;
	/// @dev Nonce to be used as replay protection for the order
	uint256 nonce;
	/// @dev The chainId of the origin chain
	uint32 originChainId;
	/// @dev The timestamp by which the order must be initiated
	uint32 initiateDeadline;
	/// @dev The timestamp by which the order must be filled on the destination chain(s)
	uint32 fillDeadline;

	/// @dev The inputs to be taken from the swapper as part of order initiation
	Input[] swapperInputs;
	/// @dev The outputs to be given to the swapper as part of order fulfillment
	Output[] swapperOutputs;
	/// @dev The outputs to be given to the filler as part of order settlement
	Output[] fillerOutputs;
}

/// @notice Tokens sent by the swapper as inputs to the order
struct Input {
	/// @dev The address of the ERC20 token on the origin chain
	address token;
	/// @dev The amount of the token to be sent
	uint256 amount;
}

/// @notice Tokens that must be receive for a valid order fulfillment
struct Output {
	/// @dev The address of the ERC20 token on the destination chain
	/// @dev address(0) used as a sentinel for the native token
	address token;
	/// @dev The amount of the token to be sent
	uint256 amount;
	/// @dev The address to receive the output tokens
	address recipient;
	/// @dev The destination chain for this output
	uint32 chainId;
}

ISettlementContract interface

A compliant settlement contract implementation MUST implement the ISettlementContract interface:

/// @title ISettlementContract
/// @notice Standard interface for settlement contracts
interface ISettlementContract {
	/// @notice Initiates the settlement of a cross-chain order
	/// @dev To be called by the filler
	/// @param order The CrossChainOrder definition
	/// @param signature The swapper's signature over the order
	/// @param fillerData Any filler-defined data required by the settler
	function initiate(CrossChainOrder order, bytes signature, bytes fillerData) external;

	/// @notice Resolves a specific CrossChainOrder into a generic ResolvedCrossChainOrder
	/// @dev Intended to improve standardized integration of various order types and settlement contracts
	/// @param order The CrossChainOrder definition
	/// @param fillerData Any filler-defined data required by the settler
	/// @returns ResolvedCrossChainOrder hydrated order data including the inputs and outputs of the order
	function resolve(CrossChainOrder order, bytes fillerData) external view returns (ResolvedCrossChainOrder);
}

Rationale

Generic OrderData

A key consideration is to ensure that a broad range of cross-chain intent designs can work within the same standard. To enable this, the specification is designed around a standard cross-chain intents flow, while allowing for varying implementation details within that flow.

Standard cross-chain intents flow:

  1. The swapper signs an off-chain message defining the parameters of their order
  2. The order is disseminated to fillers
  3. The filler initiates the trade on the origin chain
  4. The filler fills the order on the destination chain
  5. A cross-chain settlement process takes place to settle the order

Within this flow, implementers of the standard have design flexibility to customize behavior such as:

  • Price resolution, e.g. dutch auctions or oracle-based pricing
  • Fulfillment constraints
  • Settlement procedures.

The orderData field allows implementations to take arbitrary specifications for these behaviors while still enabling integrators to parse the primary fields of the order.

This functionality also motivated the resolve view function and ResolvedCrossChainOrder type. Resolution enables integrating fillers to validate and assess orders without specific knowledge of the orderData field at hand.

Usage of Permit2

Permit2 is not specifically required by this standard, but does provide an efficient and straightforward approach to building standard-adherent protocols. Specifically, the witness functions of permit2 allow swappers to both approve the token transfer and the order itself with a single signature. This also nicely couples the transfer of tokens with a successful initiation of the order.

In contrast, a standard approval model would require two separate signatures - a token approval (either ERC-2612 or on-chain) and a signature to approve the terms of the swap. It also decouples the token approval from the swap, meaning approved tokens could potentially be taken at any time due to a buggy or untrusted settler contract.

When building a standard-compliant settler system around Permit2, the following considerations should be made

  • nonce in the order struct should be a permit2 nonce
  • initiateDeadline in the order struct should be the permit2 deadline
  • A full order struct including the parsed orderData should be used as the witness type during the permit2 call. This ensures maximum transparency to the swapper as they sign their order permit.

Security Considerations

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Mark Toda (@marktoda), Matt Rice (@mrice32), Nick Pai (@nicholaspai), "ERC-7683: Cross Chain Intents [DRAFT]," Ethereum Improvement Proposals, no. 7683, April 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7683.