Introduction

Executive Summary

Purpose

The Enterprise Ethereum Alliance (EEA) Distributed Ledger Technology Interoperability Specification aims to establish a secure and efficient framework for interoperability between different blockchain networks, focusing on enterprise applications. This specification addresses the need for various blockchain platforms to interact and transact seamlessly, especially in complex and regulated sectors like financial services and supply chain management. The specification includes architectural guidelines, protocol stack, and interfaces definitions, which are crucial for asset and data exchange across different blockchain systems, thereby enhancing their functionality and utility.

It is designed to support enterprise blockchain networks using diverse underlying technologies (for example EVM and non-EVM networks), facilitating complex multi-chain ecosystem deployments involving assets, payments, and securities transactions. The open standard prevents fragmentation across different vendor implementations. Use cases include currency exchanges between blockchains with different tokens, coordinating securities transfers with payment transfers on different networks, and atomic swaps/transfers of digital assets. The specification aims to support regulated enterprise use cases that require interoperability between multiple blockchains with secure guarantees.

This document is produced and maintained by the EEA Inc.'s Crosschain Interoperability Working Group. This version is a Public Exposure Draft for comment, and we welcome feedback to help improve it, and to help the Working Group understand how it has been useful in specific cases.

Intended Audience

This specification is relevant to three primary stakeholder groups:
  • Developers, Architects, Integrators: The specification provides interfaces to accelerate the development of interchangeable components for connecting heterogeneous distributed ledger technologies and blockchain networks. It is relevant to professionals seeking to implement interoperability solutions across various DLT platforms, building or looking to incorporate interoperability solutions into their solutions and applications.
  • Decision-makers and IT executives: Executives and decision-makers in regulated industries such as finance, healthcare, and supply chain will find this specification crucial for unlocking new business models and value streams through interoperable blockchain solutions. Executive in corporations that are exploring or already using DLT technologies in their operations are key beneficiaries of this specification.
  • Regulators and Standards Development Organizations (SDOs): By setting a precedent for interoperability standards, this document aids regulators and SDOs in understanding the technical complexities and potential regulatory considerations of crosschain communications. It aims to foster a collaborative environment where regulatory frameworks can evolve in tandem with technological advancements, ensuring a balanced approach to innovation and regulations.

Structure of this document

The core content of this document is (currently) structured in several sections: - : An overview of the Crosschain Interoperability stack and description of its layered architecture. - : The requirements and interfaces to enable trusted exchange of data and events between chains, ensuring integrity and validity of information passing between networks. - : The requirements and interfaces to enable execution of operations across chains, allowing crosschain applications to trigger and coordinate activities on multiple networks. - : The requirements and interfaces to implement business logic and use case-specific functionality. Definitions are generally provided the first time a term is used in the content, and then other uses of the defined term link to that definition. There are appendices that collect and revise useful information such as terms defined, or good practice recommendations.

Status of this document

This is a working document. It is inappropriate to cite this document other than as a work in progress. Please send any comments to the editors of this document.

This document is available under the terms of the Apache License 2.0. When referencing this document, the following citation format should be used:

[eeaciw-crosschainspec-v1.0] EEA CIW - Distributed Ledger Technology Interoperability Specification Draft Version 1.0. Edited by Weijia Zhang, Marelize Kriel, Anais Ofranc. 28 February 2022. EEA CIW. https://entethalliance.github.io/crosschain-interoperability/draft_dlt-interop_techspec.html .

Github Issues are preferred for discussion of this document.

Architecture of the Crosschain Protocol Stack

The architecture of the crosschain interoperability stack provides a standardized framework to enable secure and seamless communication across diverse blockchain and/or DLT networks. It consists of a modular, plug-and-play architecture spanning three layers - Crosschain Applications, Crosschain Function Calls, and Crosschain Messaging. The layered architecture allows for the integration of components from different vendors, serving as a robust infrastructure for an array of crosschain applications.

Crosschain Protocol Stack

Figure 1: Crosschain Protocol - Layered Architecture

Together, these three layers form a protocol stack that is robust, versatile, and capable of addressing the complex needs of modern enterprises. By adhering to the Distributed Ledger Technology Interoperability Specification defined by the Enterprise Ethereum Alliance (EEA), the protocol stack ensures that the components are not only interoperable but also scalable and secure. The EEA’s specification is a formal definition of the implementation requirements for Enterprise Ethereum clients to achieve secure and scalable crosschain communications.

The primary focus of the current specification is on Ethereum Virtual Machine (EVM) compatible blockchains, reflecting the widespread adoption and development within the Ethereum ecosystem. The specification is however implementable and compatible with other architectures, such as ZKP compatible networks and R3 Corda, where network state updates can be verified with an EEA-compliant proof. This broad-minded approach indicates a commitment to future-proofing interoperability standards and catering to an evolving digital ecosystem.

Crosschain Messaging Layer

The Crosschain Messaging layer establishes the critical information infrastructure to enable trusted interoperation between blockchain or DLT networks.

This section describes the required protocols, message formats, and mechanisms for one network to prove the integrity and authenticity of data to another. This includes specifics around event-based, state-based, and transaction-based messaging to cater to diverse crosschain information exchange requirements. Additionally, the section covers format standards for crosschain proofs and considerations for secure transmission of verified data between networks.

Crosschain message relays

This section describes various mechanisms through which messages are relayed from one blockchain to another, ensuring that the information can be trusted. This is fundamental to the operation of crosschain functions because the reliability and security of crosschain operations depend on the integrity of the message relay methods.

Understanding the strengths and weaknesses of various approaches is setting an important context for later understanding the technical requirements around event-based, state-based, and transaction-based messaging.

| Setup | Mechanism | Security | Decentralization | Ease of use | Computation | Scalability | | -------- | ------- | ------- | ------- | ------- | ------- | ------- | | Multisig | Governance | Aggregation of Signatures | High. Admin addresses safeguarding | Depending on admin nodes. | Easy | Light | High | | MPC | DKG | Schnorr Signature | Group address safeguarding | Depending on validator nodes. | Easy | Light | High | | ZKP Snark | Trusted Ceremony | Setup dependent proof key and verfication key | Dependent on secure setup | Medium. More centralized proofer | Difficult | Heavy | Low | | ZKP Stark | No trusted setup needed | Proof and verification independent of external parameter | High security | Medium. More centralized proofer | Difficult | Heavy | Low | | Oracle | Collaboration | Smart Contract callback | Trusted Oracle nodes | Medium | Easy | Medium | High | | Light Client | Weak subjectivity | Header and state verification | High security | No additional trusted actors needed | Medium to Difficult | Medium | High | | Hybrid method | Dual Channel | Cross checking | Extra security | High | Medium | Medium | Medium |

Crosschain message definition

A crosschain message can be categorized, based on the underlying network characteristic, as listed below:

Crosschain verifier interface

Message verification is done by the Crosschain Messaging layer by implementing the following interface and function.

Messaging components MUST support the Solidity ICrosschainVerifier interface described in section 3.3 Crosschain verifier interface.

        
pragma solidity >=0.8; interface ICrosschainVerifier { function decodeAndVerify( uint256 networkId, bytes calldata encodedInfo, bytes calldata encodedProof ) external view returns ( bytes memory decodedInfo ); }

The function decodeAndVerify is used to decode and verify message information originating from different networks.

Parameters:

Returns:

The function (optionally) returns decoded information for practical purposes. To improve efficiency and to avoid another smart contract call to a verifier contract implementation that performs scheme specific decoding of event data.

If the verification fails for any reason, the verification failure must prevent any state changes from occurring.

The transaction MUST fail if the verification fails.

Some example failure cases requiring a transaction revert are:

By reverting on failed verification, the system ensures data integrity and prevents invalid data from being processed.

Solidity's require() or revert() functions SHOULD be used to revert when verification fails.

Custom error codes and messages are RECOMMENDED to provide details on the failure reason.

Event-based messaging mechanism

In an EVM-based environment, event attestation is a process that utilizes the block header's receipt root to prove that events occurred within that particular block. This receipt root is a cryptographic commitment to the list of transaction receipts, which in turn contain the smart contract event logs. The event data would typically contain information to trigger an action on the destination network.

Event-based Verification

Whenever a smart contract emits an event on the source network, the associated log data is written and recorded in a transaction receipt. Receipts are hashed and represented as leaves in a Merkle tree of which root is called the receipt root. This receipt root is included in each block header and used when verifying Merkle tree membership of a specific receipt containing a specific event log. This serves as a reliable way to prove that an event has indeed been emitted on the source network.

A verifying smart contract, designed to handle crosschain messages, deployed on the destination network can use this event data to execute a corresponding operation after verifying the authenticity of the event. The verifying contract will perform a validation check, by means of a Merkle inclusion proof, to verify that the event data is part of a transaction receipt that corresponds to a receipt root in a block header that the destination network recognizes as valid. This process ensures that only verified events from the source network can trigger actions on the destination network.

Event-based Interface

For event-based implementations, the decodeAndVerify function of the Solidity ICrosschainVerifier interface described in section 3.3 Crosschain verifier interface MUST be used to decode and verify event information.

Parameters:

Returns:

Event Attestation

The process for using event attestation in the Crosschain Messaging Protocol can be summarised as follows.

  1. The Crosschain Function Call contract on the source network emits an event. The circumstances in which an event is emitted and the meaning of the event are Crosschain Function Call protocol dependant. This event can then be verified on one or more target networks.
  2. Relayer nodes observe the network, for events being emitted by the Crosschain Function Call contract. Once an event is observed, they can either sign the event and store it locally, or wrap the event with a block header Merkle proof before sending it to the target network for verification.
  3. The Crosschain Function Call SDK can be used to observe the network for events being emitted by the Crosschain Function Call contract. When an event is observed, it needs to be wrapped up with a proof so that it can be verified on another network. It can call the Crosschain Messaging Layer SDK to fetch signed events from relayers and combine them as a single, signed object. The number of signatures that need to be combined will depend on the threshold signature scheme for the source network. It can alternatively call the Crosschain Messaging Layer SDK to construct a block header proof around the event making use of validator signatures on the source network.
  4. The Crosschain Function Call SDK can be used to submit a transaction to the target network, calling the Crosschain Function Call contract, supplying the event and proof that it occurred. The Crosschain Function Call contract calls the Crosschain Messaging contract, for the given source network, invoking decodeAndVerify. This call verifies that the event information did come from the source network and that the event data can be trusted. Actions taken after decoding and verifying the message are Crosschain Function Call protocol dependant.

State-based messaging mechanism

For EVM-based networks, state-based messaging relies on the state root in block headers to prove the current state of the source network. By conveying state roots for particular blocks alongside expected state data encodings, the destination network can verify specific account balances, contract variables, or other on-chain data stored in the source network's state tree.

For networks using ZKPs, state updates can be attested through computationally verifiable proofs validating changes to the network state. The ZKP prover can succinctly demonstrate a particular account balance or contract storage value transitioned to an expected amount from a previously verified state, while keeping state data opaque.

State-based Verification

Block header proofs for state-based messaging can be used in exactly the same manner as in event-based messaging but unlike events in transaction receipts, the current header includes states in the past. ZKP circuit specific contracts can be used for verification of state changes for ZKP capable source networks.

State-based Interface

For state-based implementations, the decodeAndVerify function of the Solidity ICrosschainVerifier interface described in section 3.3 Crosschain verifier interface MUST be used to decode and verify storage root information.

Parameters:

Returns:

Transaction-based messaging mechanism

Transaction-based crosschain messaging relies on conveying transaction information that can be used to prove that a transaction was executed on the source network. For EVM-based networks, the transaction root in block headers provides a cryptographic hash structure encapsulating all transactions included within the block. By transmitting block headers containing a desired transaction hash alongside a Merkle proof tying the transaction hash to the overall transaction root, the destination network can reliably verify the occurrence of the specific transaction on the source network.

More broadly, any network that utilizes Merkle trees or similar structures to efficiently store and verify transactions, can be used in the crosschain messaging protocol to attest that transactions were executed in the network.

Transaction-based Verification

Block header proofs for transaction-based messaging can be used in exactly the same manner as in event-based messaging by making use of the transaction root. Moreover, a transaction executed in a source network, that is not EVM-based, can be wrapped in the same way with a Merkle inclusion proof or a ZKP depending on the capabilities of the source network.

Transaction-based Interface

For transaction-based implementations, the decodeAndVerify function of the Solidity ICrosschainVerifier interface described in section 3.3 Crosschain verifier interface MUST be used to decode and verify event information.

Parameters:

Returns:

Transaction-based Attestation

The process for using transaction or state attestation in the Crosschain Messaging Protocol can be applied in a similar way as event attestation for EVM compatible networks. It is also possible to construct proofs to be used for transaction or state attestation from non-EVM networks. It can be summarised as follows.

  1. A transaction was executed or global state was updated on the source network. This transaction or state change can then be verified on one or more target networks.
  2. Relayer nodes observe the network, for transactions being executed or storage roots being updated. Once a transaction or state change is observed, they can either sign it and store it locally, or wrap it with a Merkle proof or ZKP before sending it to the target network for verification.
  3. The Crosschain Function Call SDK can be used to observe the network for transactions or state changes. Once observed, it needs to be wrapped up with a proof so that it can be verified on another network. It can call the Crosschain Messaging Layer SDK to fetch signed transactions or state changes from relayers and combine them as a single, signed object. The number of signatures that need to be combined will depend on the threshold signature scheme for the source network. It can alternatively also call the Crosschain Messaging Layer SDK to construct a block header proof around the transaction or state roots, making use of validator signatures on the source network, or more generally, construct a Merkle inclusion proof making use of the consensus participants of the source network. For ZKP capable networks, the Crosschain Messaging Layer SDK can also be called to produce a ZKP to computationally verify that the transaction or state change is valid.
  4. The Crosschain Function Call SDK can be used to submit a transaction to the target network, calling the Crosschain Function Call contract, supplying the transaction or state update along with a proof that it occurred. The Crosschain Function Call contract calls the Crosschain Messaging contract, for the given source network, invoking decodeAndVerify. This call verifies that the information did come from the source network and its contents can be trusted. Actions taken after decoding and verifying the message are Crosschain Function Call protocol dependant.

Formats of Proofs

The sections below detail the requirements for formats of proofs.

Transaction-based messaging components MUST support at least one of the formats of proofs:

Multiple ECDSA Signatures

For implementations supporting multiple ECDSA signatures, encodedProof MUST contain an array of ECDSA signatures with metadata, with each signature tied to a unique signer address. The encodedProof value for a scenario requiring one or more ECDSA signatures has the format described in section 3.7.1. It contains the ABI-encoded Proof struct as defined in that section.

        
pragma solidity >=0.8; struct Signature { uint256 by; uint256 sigR; uint256 sigS; uint256 sigV; bytes32 meta; } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Note:

Multiple EDDSA Signatures

For implementations supporting multiple EDDSA signatures, encodedProof MUST contain an array of EDDSA signatures with metadata, with each signature tied to a unique signer public key. The encodedProof value for a scenario requiring one or more EDDSA signatures has the format described in this section. It contains the ABI-encoded Proof struct as defined below.

      
pragma solidity >=0.8; struct Signature { uint256 by; uint256 sigR; uint256 sigS; uint256 sigV; bytes meta; } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Note:

Multiple Schnorr Signatures

For implementations supporting multiple Schnorr signatures, encodedProof MUST contain an array of Schnorr signatures with metadata, with each signature tied to a unique signer public key. The encodedProof value for a scenario requiring one or more Schnorr signatures has the format described in this section. It contains the ABI-encoded Proof struct as defined below.

      
pragma solidity >=0.8; struct Signature { uint256 by; uint256 sigR; uint256 sigS; uint256 sigV; bytes32 meta; } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Note:

Multiple BLS Signatures

For implementations supporting multiple BLS signatures, encodedProof MUST contain an array of BLS signatures with metadata, with each signature tied to a unique signer public key. The encodedProof value for a scenario requiring one or more EDDSA signatures has the format described in this section. It contains the ABI-encoded Proof struct as defined below.

      
pragma solidity >=0.8; struct Signature { uint512 by; uint256 sigR; uint256 sigS; uint256 sigV; bytes32 meta; } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Note:

Ethereum Block Header Proofs

For implementations supporting Ethereum block header proofs, encodedProof MUST contain Merkle Patricia proof data and an array of Ethereum validator signatures. The encodedProof value for a scenario, requiring a Merkle Patricia proof and one or more validator signatures, has the format described in this section. It contains the ABI-encoded Proof struct as defined below.

        
pragma solidity >=0.8; struct ProofData { bytes witnesses; bytes32 root; bytes32 blockHash; bytes blockHeaderMeta; } struct Signature { uint256 by; uint256 sigR; uint256 sigS; uint256 sigV; bytes32 meta; } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Multivalued Merkle Inclusion Proofs

For implementations supporting multivalued Merkle inclusion proofs, encodedProof MUST contain a multivalued Merkle proof and an array of heterogeneous participant signatures. The encodedProof value for a scenario, requiring a multivalued Merkle proof and one or more heterogeneous participant signatures, has the format described in this section. It contains the ABI-encoded Proof struct as defined below.

        
pragma solidity >=0.8; struct ProofData { bytes32 root; bytes32[] witnesses; uint8[] flags; bytes32[] values; } struct Signature { uint256 by; uint256 sigR; uint256 sigS; uint256 sigV; bytes32 meta; } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Zero-knowledge Proofs

For implementations supporting zero-knowledge proofs, encodedProof MUST contain the data points required for the zero-knowledge circuit being used. The encodedProof value for a scenario requiring a zero-knowledge proof has the format described in section 3.7.5. It contains the ABI-encoded Proof struct as defined in that section, including elliptic curve pairing points required for the particular zero-knowledge circuit implementation.

        
pragma solidity >=0.8; struct G1 { uint x; uint y; } struct G2 { uint[2] x; uint[2] y; } struct ProofData { G1 a; G2 b; G1 c; bytes32 meta } struct Proof { uint256 typ; bytes proofData; Signature[] signatures; }

Where:

Crosschain transaction fees

When messages are relayed across networks, certain crosschain messaging models entail associated fees. In event-based transfers validated by third-party relayers, the relayers may charge a service fee plus cover gas costs for submitting proofs on destination chains. To enable transparency, a EstimateFee function can be exposed to return expected messaging fees based on payload details. It can accept parameters like the target network ID and estimated gas limit for proof verification. Using these inputs, it can calculate total fees comprising:

The estimated fees returned can inform source network applications on complete crosschain messaging costs denominated in the payload asset. Upon successful relaying, fees are paid to the relaying contract and distributed to participating relayers minus gas expenses. For non-relayed state-based transfers where users directly submit proofs, the function can return just the target network gas estimation required for proof verification. Enabling fee transparency and estimation guides rational messaging behavior across networks.

For messaging models requiring fees, components MUST support the IEstimateGas interface.

  
pragma solidity >=0.8; interface IEstimateGas { function estimateGas( uint256 networkId, uint256 gasLimit, bytes data ) external returns (uint256 gas); }

Where:

Crosschain messaging considerations

Levels of Finality

Settlement Finality: Settlement finality refers to the point at which a transaction is considered complete and irreversible by the system. Once a transaction achieves finality, it cannot be altered, undone, or disputed. This is a critical requirement for many financial and legal applications where certainty about the status of a transaction is necessary.

Probabilistic Finality: Probabilistic finality means that transactions become increasingly irreversible as more blocks are added to the chain after the block containing the transaction. The security of a transaction is based on the probability that it would be too computationally expensive for an attacker to change the transaction, as they would need to redo the work of the block containing the transaction and all subsequent blocks. Probabilistic finality usually occurs in DLTs that use consensus mechanisms with potential forks, like proof-of-work blockchains.

In industries heavily regulated and requiring clear audit trails (like finance and law), settlement finality is often a legal requirement. Systems operating in these domains must ensure their technology can meet these regulatory standards, making probabilistic finality unsuitable.

In addition, for DLT systems that interact with traditional banking systems or other blockchains, having clear settlement finality can simplify the process of reconciling transactions across different systems, which might have different rules regarding transaction finality.

Level of finality for public permissionless networks.

Implementations must carefully navigate the unique characteristics of the DLT networks on which they operate, ensuring that messages and transactions maintain their integrity and legal standing as they traverse across different ledger systems, and must account for the potential variations in the time to finality and the economic implications of the consensus mechanisms. For instance, in the context of public permissionless networks utilizing Proof of Stake (PoS) for consensus, such as Ethereum post-Merge, the network offers a form of deterministic finality through mechanisms like the Casper Finality Gadget, where transactions are considered final and irreversible after a certain number of confirmations, backed by economic stakes of validators. This ensures that transactions cannot be reversed without significant financial penalties, providing a stronger assurance of finality compared to probabilistic finality seen in proof-of-work systems.

Level of finality for permissioned networks.

In permissioned networks with consensus mechanisms like proof of authority, immediate deterministic finality can be assumed for chain transactions with sufficient validator signatures. Byzantine fault tolerance provides strong cryptographic guarantees against block reversions. Thus, messaging finality can directly track on-chain settlement without probabilistic relaxations on permissioned environments using consensus algorithms with instant finality. Deferred effects should only be needed in cases of detected validation failures, not due to probabilistic uncertainties.

Public Key / Address Validation

Some crosschain messaging techniques rely on cryptographic signatures to attest to the validity of data sourced from external networks. Destination networks will typically maintain a list of authorized public keys alongside verification rules in their verifier contracts. These contracts will also govern permissions to add or remove trusted keys from the whitelist based on the sender's address.

For ECDSA signatures, verifier contracts may opt to rather store Ethereum addresses, serving as proxies for actual public keys, to be used later in verifying signed payloads. Before registering their signing address, participants must validate possession of the associated private key for signing messages, usually via an eth_sign or EIP-191 personal_sign operation. Failing to properly validate the signing identity can bind an invalid address incapable of producing signatures to manage the registrant’s listing. This prevents erroneously registered entities from later participating in their own removal or updating their registered signing keys. Careful key management ensures signature-based messaging can flexibly propagate while preventing spam and manipulation.

Consideration of ZKP as a messaging mechanism

ZK-SNARKs are succinct non-interactive arguments of knowledge that enable privacy-preserving proofs of computation and integrity. They are well-suited for crosschain messaging due to their short, efficiently verifiable proofs. ZKP relayers are operators that generate proofs to attest to the validity of messages without revealing the content. They undergo upfront ceremonies to securely generate proving and verification keys to facilitating subsequent proof generation workflows. The verification keys are published or configured in smart contracts on the destination network in order to verify computational proofs attesting to the authenticity of ZKP-encoded messages coming from the source network.

For crosschain messaging, ZKP relayers follow bi-directional multi-party computation protocols to jointly compute proofs of events, transactions or state transitions on source networks without leaking raw data. Source network integrity assertions are encoded into the generated proofs and transmitted to ZK verifier contracts on destination networks for verification against the published verification keys.

Destination networks can host ZK verifier contracts supporting different proof circuits for multiple types of ZKP-attested crosschain messages such as asset transfers, trade settlements, identity credentials, etc. By configuring circuit-specific verifier contracts and relayers with aligned circuits, advanced ZKP-based messaging flows between networks can be supported without compromising privacy.

Crosschain Function Call Layer

The Crosschain Function Calls layer enables execution of operations across networks, allowing crosschain applications to trigger and coordinate activities on multiple networks. This is the operational core of the stack, enabling functions to be executed remotely on another network. This capability is crucial for allowing synchronous workflows across networks in scenarios where actions on one network depend on the state or outcomes on another. It is this layer that orchestrates the remote execution of smart contract functions, ensuring that transactions are not only executed but done so in a manner that aligns with the overarching business logic defined in the applications layer.

Crosschain function call protocols can be atomic or non-atomic. Non-atomic protocols do not ensure consistency across networks. That is, a segment of the overall crosschain flow may occur on a source network, with associated updates, but the segment on the destination network may fail, and hence the updates would not be applied on the destination network. A crosschain flow segment could fail for any of the reasons described below.

Non-atomic protocols MUST provide a mechanism to resolve failures such that consistency is restored.

Interfaces and Helper Functions

This section defines Solidity interfaces for the Crosschain Function Call layer as used by the Crosschain Application layer.

Crosschain Function Call Interface

The Crosschain Function Call interface allows applications to call functions remotely on other networks.

Implementations MUST support the ICrosschainFunctionCall Solidity interface described in this section.

      
pragma solidity >=0.8; interface ICrosschainFunctionCall { function outboundCall( uint256 networkId, address contractAddress, bytes calldata functionCallData ) external payable; function inboundCall( uint256 networkId, bytes calldata encodedInfo, bytes calldata encodedProof, ) external payable; event CrosschainFunctionCall( uint256 indexed networkId, address indexed contractAddress, bytes functionCallData ); }

Where ICrosschainFunctionCall functions are defined as:

Where outboundCall parameters are defined as:

And inboundCall parameters are defined as:

Proofs should always be generated for a specific source and destination network as a remote function call is always intended for a particular target network. It is recommended to include the networkId in the source network encodedInfo that will be attested to on another network so that it cannot be tampered with and that the remote function call is executed in the intended network.

Task Manager Interface

When a task is dispatched from the source network, by calling outboundCall, a remote function call is triggered on the target network. This process should be made idempotent in the sense that if identical remote function call requests are made, with the same source network information and attestation proof, then it should only be executed once. There are various approaches to implementing this. One solution would be to store hashes of the given encodedInfo on the target network, to ensure it is used only once to facilitate a successful remote function call execution. Another solution would be to make use of a task identifier, generated to be unique to the source network information, and to persist the identifiers of successfully executed tasks on the target network.

Implementations MAY choose to support the ITaskManager Solidity interface described in this section.

    
pragma solidity >=0.8; interface ITaskManager { event OutboundTaskExecuted( bytes32 indexed taskId, uint256 indexed networkId, address indexed contractAddress, bytes functionCallData ); event InboundTaskExecuted( bytes32 indexed taskId, uint256 indexed networkId, address indexed contractAddress, bytes functionCallData ); function genTaskId(bytes calldata data) external pure returns (bytes32 taskId); }

Where ITaskManager events are defined as:

Where OutboundTaskExecuted parameters are defined as:

And InboundTaskExecuted parameters are defined as:

Application Authentication Parameters

Remote function call components need to determine the source network and contract address that initiated the remote function call. Functions in contracts on destination networks use this information to determine if the caller is authorised to execute the function remotely. The authentication parameters are provided as hidden parameters, that exist outside the scope of the declared function parameters. The parameters are appended to the call data of a function by the function call component and extracted by the application layer.

Implementations MUST append the hidden authentication parameters to the function call data before emitting the event.

The helper function encodeAuthParams appends authentication parameters to the function selector and parameter data, and the function decodeAuthParams can be used to extract the authentication parameters from the call data again.

      
pragma solidity >=0.8; abstract contract AuthParams{ function encodeAuthParams( uint256 networkId, address contractAddress, bytes memory functionCallData ) internal pure returns (bytes memory) { return bytes.concat(functionCallData, abi.encodePacked(networkId, contractAddress)); } function decodeAuthParams() internal pure returns ( uint256 networkId, address contractAddress ) { bytes calldata allParams = msg.data; uint256 len = allParams.length; assembly { calldatacopy(0x0, sub(len, 52), 32) networkId := mload(0) calldatacopy(12, sub(len, 20), 20) contractAddress := mload(0) } } }
Application Authentication

Similar to existing single network applications, the type of application authentication is application specific. Applications that checked msg.sender in a single network context should use the decodeAuthParams to check that the source network and source contract are authorised to call the function.

Crosschain Application Layer

The Crosschain Application Layer orchestrates complex interactions across multiple blockchain networks, enabling business processes to seamlessly operate over distinct ledgers. This layer empowers applications to access and manipulate data across different networks, unlocking new possibilities for crosschain interoperability and collaboration. It utilizes crosschain function calls to facilitate remote function executions and state updates across networks.

The Crosschain Application layer is a user-interfacing layer compromising the following components:

The Crosschain Application Layer enables a wide range of use cases, such as crosschain asset transfers, multi-chain decentralized applications (dApps), and interoperable decentralized finance (DeFi) protocols. By facilitating seamless interaction between different DLT networks, this layer plays a crucial role in driving the adoption and scalability of this technology.

Leveraging Crosschain Messaging only

For the Crosschain Application layer to leverage the Crosschain Messaging layer defined in this specification, a Crosschain Messaging framework or SDK should be deployed alongside the source and target networks and the protocols defined in this specification should be implemented.

By leveraging the Crosschain Messaging layer, the Crosschain Application layer enables secure and reliable communication between different DLT networks. This communication is essential for executing complex, multi-chain business processes and facilitating interoperability across diverse DLT ecosystems.

Leveraging Crosschain Function Call

For the Crosschain Application layer to leverage the Crosschain Functional Call layer defined in this specification, a Crosschain Function Call Framework or SDK should be deployed, alongside the source and target networks, and the protocols defined in this specification should be implemented.

By leveraging the Crosschain Function Call layer, the Crosschain Application layer can support a wide range of complex, multi-chain use cases. This includes scenarios such as crosschain asset swaps, multi-chain lending and borrowing, and interoperable decentralized exchanges.

Crosschain Protocol Flow

Figure 2: Crosschain Protocol - Flow Overview

Considerations:

Key considerations for the Crosschain Application layer include:

Adaptability for Non-EVM Ecosystems

To ensure broad applicability and compatibility with non-EVM ecosystems, implementations of this specification in environments such as WebAssembly (WASM) or other smart contract platforms MUST provide equivalent interfaces and functions that adhere to the described behavior and semantics.

While the exact syntax may differ depending on the specific programming language and runtime environment, the core functionality, input parameters, and return values SHOULD be analogous to those defined in the Solidity interfaces within this specification.

This requirement allows developers to implement the crosschain interoperability protocols consistently across diverse DLT ecosystems, promoting seamless integration and interaction between different networks. By providing clear mappings and adaptations of the interfaces to their respective environments, non-EVM platforms can ensure that the crosschain communication mechanisms operate predictably and reliably, regardless of the underlying technology stack.

Considerations

Smart Contract Upgradability

Smart contract upgradability a critical aspect to consider in the development of a DLT interoperability implementation, particularly for long-term viability and compliance with evolving regulatory standards. Smart contracts, once deployed, are immutable on the ledger. However, financial regulations and business logic may evolve, necessitating updates to the contracts. Implementing upgradable smart contracts through proxy patterns or versioning systems allows for the modification of contract logic without changing the contract's address or deployed bytecode. This approach must be carefully designed to maintain the integrity and security of the contracts, especially in a regulated financial context. Upgradability mechanisms should include strong governance processes to control updates and prevent unauthorized changes. Additionally, considering the crosschain interoperability, the upgradability strategy should ensure consistency and compatibility across different DLT platforms, enabling seamless interaction and compliance with regulatory changes over time.

Data Type Convertibility and Compatibility

In the context of this specification, certain data types such as uint256 and bytes32 are used to define interfaces and data structures. It is important to note that these data types, while distinct, are convertible and can be transformed from one to another through simple data format conversions. Smart contracts and off-chain relays are recommended to accommodate both data types to enhance interoperability and flexibility in data handling across different DLT platforms. This approach facilitates seamless crosschain communication and operations, ensuring broader compatibility and ease of implementation within diverse DTL ecosystems. Developers should ensure that their implementations incorporate mechanisms for the straightforward conversion between these data types, where necessary, to maintain the integrity and fidelity of data as it moves across network boundaries.

Appendix

Compatibility with Algorand network

Using the crosschain messaging protocol described in this specification to facilitate interoperability between an Algorand network and an EVM-based network is outlined in this section.

Crosschain Messaging Layer

For Algorand to be compatible with the crosschain messaging protocol discussed in this document, it must support an event, transaction or state attestation proof as specified in section 3.7.

An Algorand block contains a transaction root, which authenticates the set of transactions appearing in the block, as the root of a Merkle tree with transaction ids as leaves, in lexicographic order. This can naturally be turned into a transaction attestation proof

An Algorand state proof is a cryptographic proof of state changes that occur in a given set of blocks. State proofs are created and signed by the Algorand network itself, so they can be used to verify that a state change happened on the Algorand network. State proofs use quantum-safe Falcon keys. An EVM pre-compile for verification of this signature scheme was proposed in EIP 7592 but these signature are not currently supported.

Algorand make use of events as part of log functions, which can be used in the crosschain message protocol described in this document.

Algorand uses ED25519 signature scheme for authorization and uses SHA-512/256 hash function for creating contract account addresses from TEAL bytecode.

It is recommended to support ECDSA using the SECP256K1 curve and KECCAK-256 hashing algorithm for better verification times in the EVM. As a source ledger, it would need to emit events. Since Algorand implements events in Log function, it is recommended that a module function is defined in Algorand that has a similar format as Solidity. The function should log the event data such as destination chain, destination smart contract address, and function data. Messaging components MUST support an equivalent interface as described in section 3.3 (Crosschain verifier interface). This function could be: @app.external def decodeAndVerify(networkId:abi.uint256, encodedInfo: abi.byte[], encodedProof:abi.byte[], output:abi.byte[] )-> Expr: # getDecodedInfo return output.set(decodedInfo) The definition of networkId, encodedInfo and encodedProof are similar to the EVM definition. To perform encoding for message info, the encoded rules of Algorand specification (https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0004.md) should be used.

Crosschain Function Call Layer

Algorand should support compatible remote function call libraries to initiate a remote function call to another network and execute a remote function call locally after verifying a proof from another network as described in section 4.1.1 (Remote Function Call Interface).

On the Algorand chain, this remote function call can be defined as @app.external def outboundCall(networkId:abi.uint256, contractAddress: abi.address, functionCallData:abi.byte[] )-> Expr def inboundCall(networkId:abi.uint256, encodedInfo: abi.byte[], encodedProof:abi.byte[] )-> Expr def CrosschainCallEvent(networkId:abi.uint256, contractAddress: abi.address, functionCallData:abi.byte[] )-> Expr

Compatibility with the Corda network

Using the crosschain messaging protocol described in this specification to facilitate interoperability between a Corda network and an Ethereum network is outlined in this section.

Crosschain Messaging Layer

Corda does not have events in the same sense as Ethereum but a transaction attestation proof can be constructed instead and used in the transaction-based messaging mechanism outlined in section 3.6.3 (Transaction-based Attestation). Corda transactions are split up into component groups and their SHA-256 hashes are used as Merkle tree leaves in storage. The most important of these, for a Corda transaction attestation proof, are listed below:

- The outputs component group, containing the output data of the transaction. - The commands component group, containing the commands that was executed during the execution of the transaction. - The signers component group, containing the public keys of all participants that needs to sign the transaction. - The notary component group, containing the public key of the notary that needs to sign the transaction.

The contents of the outputs and commands component groups is interpreted as an instruction and translated into an EVM function and corresponding function call parameters to facilitate a remote function call from a Corda network to an EVM-based network. Translation is done by registered parameter handlers for each function that is callable via the interop protocol.

Similar to the interop between two Ethereum networks, participant on-boarding will be required to provide sufficient security in a production environment. Even for EVM-based event attestation proofs, it might be necessary to maintain a list of active validators of the source network on the target network. For example, some QBFT network implementations using contract validator selection, no longer include the list of validator addresses in their block headers.

More generally, the network verifying a proof might need to maintain a list of authorized signatories in the verifying contract. Consensus on Corda transactions are reached among participants of the transaction and a notary, instead of a global network-wide validator pool. For this reason, it is necessary to verify that the signatures provided in the proof are from authorized signatories and match up with the required signers of the transaction as provided in the signers and notary component groups.

Corda signatures can use ECDSA with the SECP256K1 or SECP256R1 curve and SHA256 hashing, or EDDSA with the ED25519 curve and SHA512 hashing. Signatures are performed over a hash of the Merkle transaction tree root and metadata containing the signature scheme that was used. Proof and signature structures must use those defined in section 3.7.6 (Multivalued Merkle Inclusion Proofs).

The interface for encoding transaction data, for use in the transaction-based messaging mechanism, is given in section 3.6.2 (Transaction-based Interface). The structure of the transaction data (txData) is DLT specific and an example of a compliant Corda transaction attestation proof can make use of the following structures:

        
struct ComponentData { uint8 groupIndex; uint8 internalIndex; bytes encodedBytes; } struct TxData { bytes inputParameters; string hashAlgorithm; bytes32 privacySalt; ComponentData[] componentData; }

Where the ComponentData structure contains Corda transaction component group data that needs to be decoded, hashed and checked for Merkle tree inclusion.

Properties:

  • groupIndex: Global transaction component group index.
  • internalIndex: Internal component group index.
  • encodedBytes: Contains a hex-encoded component group of the Corda transaction.

Where the TxData structure contains the Ethereum function input parameters, Corda component group data and algorithmic details to verify the component group hash's inclusion in the transaction tree.

Properties:

  • inputParameters: Input parameters to be verified as being included in the component data.
  • hashAlgorithm: Hash algorithm used in the Merkle tree. Only SHA-256 is currently supported.
  • privacySalt: Salt needed to compute a Merkle tree leaf.
  • componentData: Hashes of these components become the values we want to proof Merkle tree membership of in our multivalued proof.

The ABI-encoded TxData struct is then included in the encodedInfo field as txData.

This multivalued Merkle inclusion proof can alternatively be turned in a zero-knowledge proof yielding a much lower EVM verification cost, with added privacy, but resource intensive proof generation.

The interface for the crosschain verifier contract on the EVM-based network, that is verifying the Corda proof, is outlined in section 3.3 (Crosschain verifier interface). To be able to fully integrate with an EVM network, a compliant Corda app would need to provide an equivalent implementation of decodeAndVerify to verify an EVM-based proof as listed in section 3.7 (Formats of Proofs). This evidently results in having to maintain an active list of EVM network validators, or authorised signatories, in the messaging layer of the Corda app.

Crosschain Function Call Layer

For every type of Corda transaction that gets added to the interop flows, and EVM function call instruction that can be created from it, a translator needs to be registered in the messaging layer. The translator consists of a mapping between Corda output component group data and EVM input function call parameters. The inputParameters in the TxData structure contains the call parameters of the function we want to call remotely through the function call layer.

Both the Corda app and the EVM contract MUST implement the interface in section 4.1.1 (Remote Function Call Interface), or an equivalent thereof, to allow functions to be called remotely on other networks.

It is worth noting that the Corda network, or the generator of the Corda proof, needs to know the destination EVM network identification and target contract address before invoking inboundCall on an EVM network. This information is not signed over as in the case of EVM event attestation, and care should be taken that the correct contract addresses are given to this layer.

The required authentication parameters in section 4.1.3 (Application Authentication Parameters) contain an additional network identification number and contract address from where the event, transaction or state change originated. This, for EVM-based networks, provide the ability to verify the source network identification and contract address against the event, transaction or state data that was signed over in an attestation proof. The most obvious way to generalize this for Corda transaction attestation proofs, at the moment, is to use the Corda network parameters. For each contract class there is a list of SHA-256 hashes, of the approved Corda app jar versions containing the contract, that is included in the Corda network parameters as whitelisted contract implementations. A Corda transaction contains a SHA-256 hash of the source network parameters from where the transaction was sent which can be used in authorisation if we onboard and maintain the Corda network parameters on the EVM-based network.

Crosschain Application Layer

The application layer integration mainly consists of implementing Corda app and EVM smart contract flows involving specific functions that can be called remotely, via the crosschain function call layer. The underlying messaging protocol, which depends on the registered verification scheme in the crosschain messaging layer, translates a verifiable step (event, transaction or state change) in the flow, performed on a remote network, into a verified instruction that can be used to securely perform the next step in the flow on the local network. The application layer contains the business logic that gets invoked through the crosschain messaging protocol.

Any application layer implementation needs to also cater for unhappy paths in the flows to ensure assets don't get stuck without recovery. This is a requirement in any regulated financial environment. This involves cancellation of a flow, under special circumstances, to release assets by means of a remote function call and a cryptographic proof of a prerequisite step that occurred on a different network.

The existing use case using Corda and Ethereum focussed in on DvP (Delivery vs Payment) where securities reside on a Corda network and tokenized cash reside on an Ethereum network in deposit token contracts. The crosschain messaging protocol is used to facilitate remote crosschain function calls between the two ledgers, and an execution plan, involving fixed flows, was build on top of the protocol to do intraday repo trades. The approach followed a standard hold to execute approach where assets and cash are placed on hold and holds are executed after verification of proof that either the hold was placed on the other network or the hold was executed on the other network.

Related work

[eeaciw-crosschainidentification-v1.0] EEA CIW - Crosschain Identification Specification Version 1.0. Edited by Weijia Zhang and Peter Robinson. 14 December 2020. EEA CIW. https://entethalliance.github.io/crosschain-interoperability/crosschainid.html . Latest stage: https://entethalliance.github.io/crosschain-interoperability/crosschainid.html .

Acknowledgments

The EEA acknowledges and thanks the many people who contributed to the development of this draft version of the specification.

Enterprise Ethereum is built on top of Ethereum, and we grateful to the entire community who develops Ethereum, for their work and their ongoing collaboration to helps us maintain as much compatibility as possible with the Ethereum ecosystem.