EEA Distributed Ledger Technology Interoperability Specification Version 1.0

EEA Publication

This Version:
https://entethalliance.org/specs/dlt-interop/v1/
Latest Published Version:
https://entethalliance.org/specs/dlt-interop/
Editors:
Weijia Zhang, PhD (Wanchain)
Marelize Kriel (Adhara)
Anaïs Ofranc (QualitaX)
EEA Contributors:
Chaals Nevile (EEA), Susumu Toriumi PhD (DataChain), Luke Riley PhD (Quant), Cosimo Bassi (Algorand), Roberto Durscki (Stellar), Thomas Hardjono PhD (MIT), Peter Robinson PhD, Ermyas Abebe PhD, Aiman Baharna (Clearmatics)

1. Introduction

1.1 Executive Summary

1.1.1 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 an EEA Publication. We welcome feedback to help improve it, and to help the Working Group understand how it has been useful in specific cases.

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

1.2 Structure of this document

The core content of this document is (currently) structured in several sections:

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.

1.3 Status of this document

This is an EEA specification, published by the Enterprise Ethereum Alliance, Inc.

This specification is licensed by the Enterprise Ethereum Alliance, Inc. (EEA) under the terms of the Apache License 2.0. Unless otherwise explicitly authorised in writing by the EEA, you can only use this specification in accordance with those terms.

When referencing this document, the following citation format should be used:

[eeaciw-crosschainspec-v1.0] EEA CIW - Distributed Ledger Technology Interoperability Specification Version 1.0. Edited by Weijia Zhang, Marelize Kriel, Anais Ofranc. 19 September 2024. EEA CIW. https://entethalliance.org/specs/dlt-interop/v1/ .

To provide feedback, please file or comment on an issue in the DLT-Interop public Github repository or use the EEA website contact page.

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

Having established the overall architecture and goals of the protocol stack, we will now provide the requirements for the foundational layer: the Crosschain Messaging Layer. This layer is crucial as it provides the underlying mechanisms for secure and verifiable communication between different blockchain networks. The following section will covers specifications related to protocols, message formats, and verification methods that enable trusted interoperation across diverse distributed ledger technologies.

3. Crosschain Messaging Layer

The Crosschain Messaging layer establishes the peer-to-peer communications infrastructure that enables 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. As several cryptographic approaches are available to afford these protections, the application developer needs to take these options into consideration when developing applications which utilize the crosschain messaging functions.

3.1 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
MPC DKG Schnorr Signature Group address safeguarding Depending on validator nodes. Easy Light
ZKP Snark Trusted Ceremony Setup dependent proof key and verfication key Dependent on secure setup Medium. More centralized proofer Difficult Heavy
ZKP Stark No trusted setup needed Proof and verification independent of external parameter High security Medium. More centralized proofer Difficult Heavy
Oracle Collaboration Smart Contract callback Trusted Oracle nodes Medium Easy Medium
Light Client Weak subjectivity Header and state verification High security No additional trusted actors needed Medium to Difficult Medium
Hybrid method Dual Channel Cross checking Extra security High Medium Medium

3.2 Crosschain message definition

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

Understanding the distinct categories of crosschain messages—whether event-based, state-based, or transaction-based—is fundamental in recognizing the complexities involved in their processing across diverse blockchain networks. To ensure these messages maintain their integrity and security during transfer, a robust verification mechanism is indispensable. This critical need for authenticating and verifying messages leads us directly to a key requirement of crosschain communication: the Crosschain verifier interface, which we will explore in section 3.3.

3.3 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:

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.

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

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

3.4.2 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:

  • networkId (required): Identification of the source network that emitted the event. This can be used to determine the verification scheme or to enforce the EIP 3220 format for EVMs.
  • encodedInfo (required): Packed ABI-encoding of the local network identifier (networkId), the local contract address (contractAddress) and the remote event data (eventData) to be verified.
  • encodedProof (required): ABI-encoded proof information and/or signatures that an implementation can use to verify the information given in eventData. The sections below detail the format of this value.

Returns:

  • decodedInfo: The decoding scheme specific data as decoded from encodedInfo. This can contain the verified local network identifier, contract address and function call data as decoded and interpreted from the given verifiable eventData, if the next action to be taken is a remote function call.

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

3.5 State-based messaging mechanism

State attestation refers to the process of verifying and certifying the correctness of a network's state at a specific point in time. The primary goal is to ensure that the data presented is accurate and has not been tampered with.

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.

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

3.5.2 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:

  • networkId (required): Identification of the source network where state was updated. This can be used to determine the applicable verification scheme.
  • encodedInfo (required): Packed ABI-encoding of the local network identifier (networkId), the local contract address (contractAddress) and the remote storage root as key-value state data (stateData) to be verified.
  • encodedProof (required): ABI-encoded proof information and/or signatures that an implementation can use to verify the information given in stateData.

Returns:

  • decodedInfo: The decoding scheme specific data as decoded from encodedInfo. This can contain the verified local network identifier, contract address and function call data as decoded and interpreted from the given verifiable stateData, if the next action to be taken is a remote function call.

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

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

3.6.2 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:

  • networkId (required): Identification of the source network where the transaction occurred. This can be used to determine the verification scheme.
  • encodedInfo (required): Packed ABI-encoding of the local network identifier (networkId), the local contract address (contractAddress) the remote transaction data (txData) to be verified.
  • encodedProof (required): ABI-encoded proof information and/or signatures that an implementation can use to verify the information given in txData. The sections below detail the format of this value.

Returns:

  • decodedInfo: The decoding scheme specific data as decoded from encodedInfo. This can contain the verified local network identifier, contract address and function call data as decoded and interpreted from the given verifiable txData, if the next action to be taken is a remote function call.

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

3.7 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 (Elliptic Curve Digital Signature Algorithm) Signatures
  • Multiple EDDSA (Edwards-curve Digital Signature Algorithm) Signatures
  • Multiple Schnorr Signatures
  • Multiple BLS Signatures
  • Ethereum Block Header Proofs
  • Multivalued Merkle Inclusion Proofs
  • Zero-knowledge Proofs

3.7.1 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:

  • by: The 160-bit Ethereum address derived from the 257-bit ECDSA public key of the signer.
  • sigR: The ECDSA signature's R value.
  • sigS: The ECDSA signature's S value.
  • sigV: The ECDSA signature's V value.
  • meta: The ECDSA signature's metadata containing optional information on the platform, curve and hash function that was used to create the signature.
  • typ: The type of proof indicating that the proof contains multiple ECDSA signatures.
  • proofData: Not applicable for this scheme.
  • signatures: An array of signatures.

Note:

  • The signatures array should only contain signatures for unique by values.

3.7.2 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:

  • by: The 256-bit EDDSA public key of the signer.
  • sigR: The EDDSA signature's R value.
  • sigS: The EDDSA signature's S value.
  • sigV: Not applicable for EDDSA signatures.
  • meta: The EDDSA signature's metadata containing optional information on the platform, curve and hash function that was used to create the signature.
  • typ: The type of proof indicating that the proof contains multiple EDDSA signatures.
  • proofData: Not applicable for this scheme.
  • signatures: An array of signatures.

Note:

  • The signatures array should only contain signatures for unique by values.

3.7.3 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:

  • by: The 256-bit Schnorr public key of the signer.
  • sigR: The EDDSA signature's R value.
  • sigS: The EDDSA signature's S value.
  • sigV: Not applicable for Schnorr signatures.
  • meta: The Schnorr signature's metadata containing optional information on the platform, curve and hash function that was used to create the signature.
  • typ: The type of proof indicating that the proof contains multiple Schnorr signatures.
  • proofData: Not applicable for this scheme.
  • signatures: An array of signatures.

Note:

  • The signatures array should only contain signatures for unique by values.

3.7.4 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:

  • by: The 384-bit BLS public key of the signer.
  • sigR: The BLS signature's alpha value.
  • sigS: Not applicable for BLS signature.
  • sigV: Not applicable for BLS signatures.
  • meta: The BLS signature's metadata containing optional information on the platform, curve and hash function that was used to create the signature.
  • typ: The type of proof indicating that the proof contains multiple EDDSA signatures.
  • proofData: Not applicable for this scheme.
  • signatures: An array of signatures.

Note:

  • The signatures array should only contain signatures for unique by values.

3.7.5 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:

  • witnesses: The rlp-encoded sibling nodes as witnesses.
  • root: The block receipt, transaction or state root.
  • blockHash: The block hash.
  • blockHeaderMeta: The rlp-encoded block header metadata.
  • by: The 160-bit Ethereum address of the signer.
  • sigR: The ECDSA signature's R value.
  • sigS: The ECDSA signature's S value.
  • sigV: The ECDSA signature's V value.
  • meta: The ECDSA signature's metadata containing optional information on the platform, curve and hashing function that was used to create the signature.
  • typ: The type of proof indicating that the proof contains Ethereum block header data.
  • proofData: ABI encoded data. The data contained in the proof, e.g. sibling nodes, receipt root, block hash and block headers.
  • signatures: The array of Ethereum validator signatures.

3.7.6 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:

  • root: The Merkle tree root.
  • witnesses: The multivalued Merkle proof's witnesses.
  • flags: The multivalued Merkle proof's flags.
  • values: The multivalued Merkle proof's leaves.
  • by: The 256-bit ECDSA public key coordinate or the 256-bit ED25519 public key of the signer.
  • sigR: The ECDSA/EDDSA signature's R value.
  • sigS: The ECDSA/EDDSA signature's S value.
  • sigV: The ECDSA signature's V value.
  • meta: The ECDSA/EDDSA signature's metadata, containing optional information on the platform, curve and hashing function that was used to create the signature.
  • typ: The type of proof indicating that the proof contains multivalued Merkle proof data.
  • proofData: The data contained in the proof, e.g. witnesses, flags, values and a root.
  • signatures: The array of consensus participant signatures.

3.7.7 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:

  • a: First elliptic curve pairing point for zero-knowledge circuit implementation.
  • b: Second elliptic curve pairing point for zero-knowledge circuit implementation.
  • c: Third elliptic curve pairing point for zero-knowledge circuit implementation.
  • meta: the public parameters, such as protocol name, base points and so on.
  • typ: The type of proof indicating that the proof contains zero-knowledge proof data.
  • proofData: The data contained in the proof, e.g. elliptic curve pairing points for a zero-knowledge circuit.
  • signatures: Not applicable for this scheme.

3.8 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:

3.9 Crosschain messaging considerations

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

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

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

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

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

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

4.1 Interfaces and Helper Functions

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

4.1.1 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:

  • outboundCall: Function that emits a CrosschainFunctionCall event, to trigger a remote function call on another network, which will only succeed if a valid EVM-based attestation proof of this event can be provided.
  • inboundCall: Function that executes a remote function call on the local network after a valid event, state or transaction attestation proof from another network was verified.

Where outboundCall parameters are defined as:

  • networkId: Identifier of remote destination network where the function call is to be made.
  • contractAddress: Address of the contract on the remote destination network to which the function call is to be made.
  • functionCallData: The function call data that consists of the ABI-encoded function selector and input parameter data with which the remote function should be called.

And inboundCall parameters are defined as:

  • networkId: Identifier of the source network that initiated the remote function call.
  • encodedInfo: The ABI-encoded remote source network information containing the local destination network identifier, contract address and function call data encoded in remote event, transaction or state change data that needs to be verified before executing the function call locally.
  • encodedProof: The ABI-encoded remote source network proof data and/or signatures that an implementation can use to verify the information given in encodedInfo.

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.

4.1.2 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:

  • OutboundTaskExecuted: Event to indicate that the outbound task was successfully executed.
  • InboundTaskExecuted: Event to indicate that the inbound task was successfully executed.

Where OutboundTaskExecuted parameters are defined as:

  • taskId: Uniquely generated task identifier.
  • networkId: Identifier of remote destination network where the function call is to be made.
  • contractAddress: Address of the contract on the remote destination network to which the function call is to be made.
  • functionCallData: The function call data with which the remote function should be called.

And InboundTaskExecuted parameters are defined as:

  • taskId: Uniquely generated task identifier.
  • networkId: Identifier of the source network that initiated the remote function call.
  • contractAddress: Address of the local contract to which the function call was made.
  • functionCallData: The function call data with which the local function was called.

4.1.3 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)
        }
      }
    }
  

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

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

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

5.2 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

5.3 Considerations

Key considerations for the Crosschain Application layer include:

6. Adaptability for other 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.

6.1 Compatibility with 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.

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

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

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

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

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

6.2.2 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

6.3 Compatibility with Stellar (Soroban) network

Using the crosschain messaging protocol described in this specification to facilitate interoperability between a Stellar (Soroban) network and an EVM-based network is outlined in this section.

6.3.1 Crosschain Messaging Layer

For Stellar(Soroban) 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.

Stellar(Soroban) make use of events as part of env struct, which can be used in the crosschain message protocol described in this document.

Messaging components MUST support an equivalent interface as described in section 3.3 (Crosschain verifier interface).

This function could be:


    pub struct Signature {
      by : U256,
      sig_r: U256,
      sig_s: U256,
      sig_v: U256,
      meta: BytesN<32>
  }

pub struct Proof { typ: U256, proof_data: Bytes, signatures: Vec, } trait ICrosschainVerifier { fn decode_and_verify(network_id: U256, encoded_info: Bytes, encoded_proof: Bytes) -> Bytes; }

The definition of networkId, encoded_info and encoded_proof are similar to the EVM definition.

6.3.2 Crosschain Function Call Layer

Stellar(Soroban) 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 Stellar(Soroban) chain, this remote function call can be defined as


  pub fn inbound_call(env: Env,
                    network_id: U256,  //stellar chainid
                    encoded_info: Bytes,
                    encoded_proof: Bytes,
      )
   fn outbound_call(env: Env, network_id: U256,target_contract_address: Bytes, function_calldata: Bytes,source_contract_address: Address );

6.4 Compatibility with Cosmos network

Using the cross-chain messaging protocol described in this specification to facilitate interoperability between a Cosmos network and an EVM-based network is outlined in this section; however, it does not define specific requirements for an EVM network to verify Cosmos proofs.

6.4.1 Crosschain Messaging Layer

The Cosmos ecosystem has a built-in Inter-Blockchain Communication (IBC) mechanism that provides a communication framework based on Light Client Verification. Specifically, IBC includes specifications for Light Clients (ICS-2), primitive communication constructs such as Connections (ICS-3), Channels/Packets (ICS-4), and the underlying Commitments (ICS-23). Full details of the protocol can be found in ICS.

6.4.1.1 Light Client in IBC

In the IBC framework, a Light Client plays a crucial role:

  • It tracks the consensus state and proof specifications of the counterparty chain.
  • It holds commitments necessary for verifying messages from the counterparty chain.

In the ICS framework, verification is divided into two main steps: 1) updateClient and 2) verifyMembership.

6.4.1.2 updateClient

updateClient is the function for updating the consensus state of the counterparty chain. While the specification is broadly defined, it can be implemented as a procedure to update from an old consensus state to a new height and new consensus state by vefifying a Header:

updateClient = {header: Header, prevConsensusState: ConsensusState} -> (NewHeight, ConsensusState)

Where ConsensusState = (root: CommitmentRoot, timestamp: uint64)

For more details on implementation, refer to Handling Client Messages in IBC.

6.4.1.3 verifyMembership

verifyMembership uses the consensus state to perform state verification. Implementations may include Merkle proof verification using accepted StateRoot. For more information on implementation, see Packet Commitment Verification in IBC.

6.4.1.4 Mapping to EEA Specification

The EEA's Crosschain Messaging Layer specification can be considered as defining the verifyMembership step. Specifically:

  • encodedProof can be viewed as an Ethereum ABI-encoded CommitmentProof as defined in ICS-23.
  • encodedInfo can be considered as the encoding of the new consensus state obtained from updateClient, along with CommitmentRoot, CommitmentPath, and Value.
  • The decodeAndVerify function can be seen as decoding these elements and internally executing verifyMembership = (root: CommitmentRoot, proof: CommitmentProof, path: CommitmentPath, value: Value) => boolean to perform state verification.

It is worth noting that the updateClient step in ICS specifies a mechanism for verifying and accepting Header. When verifying multiple Key-Value pairs against a single Header, it is beneficial from a processing efficiency standpoint to have these as separate primitives.

6.4.2 Implementation Considerations

For implementations seeking to align with ICS and fully integrate with the Cosmos network, ibc-solidity provides an EVM-compatible implementation of ICS components, including updateClient and verifyMembership.

6.5 Compatibility with the FinP2P network

Using the crosschain messaging protocol described in this specification to facilitate interoperability between an arbitrary DLT network, connected to the FinP2P network, and an Ethereum network is outlined in this section.

The FinP2P system uses routers, which serve as a connection point between different participants involved in the DLT ecosystem of tokenized assets. These routers utilize the open FinP2P protocol to unify user identities, wallets, data structures, messaging and orchestration of DLT transactions. They can be used as a network of trusted peers, signing receipts, to attest to finalized transactions on the underlying DLT networks they are connected to.

FinP2P receipts, when part of an execution plan, can be used to enable interoperability between two of the underlying DLT networks, by trusting router signatures over FinP2P receipts. This allows for a mode of interoperability where the heterogeneous DLT networks are less coupled. That is, the verifying DLT network doesn't need to understand the workings of the DLT network where the transaction originated. This means that EVM verifiers can be standardised around processing generic FinP2P receipts and verifying the signatures over them. This comes at the cost of an additional layer of trusted peers instead of relying on the consensus participants of the underlying DLT network.

The FinP2P network can also facilitate interoperability between two DLT networks by routing around ledger specific proofs, as part of the receipt, as is described in section 3.7 of this document. Verifier contracts handling such proofs will do so independently of whether the proofs were routed via FinP2P or not.

The FinP2P open source specifications are available here.

6.5.1 Crosschain Messaging Layer

A signed FinP2P receipt is encoded, hashed and signed using EIP712. Using a known Receipt structure allows the EVM verifier to extract data from the encoded structure and translate it into a command and EVM smart contract function call parameters. FinP2P receipts are defined below:


  {
    "types": {
      "EIP712Domain": [
        {"name": "name", "type": "string"},
        {"name": "version", "type": "string"},
        {"name": "chainId", "type": "uint256"},
        {"name": "verifyingContract", "type": "string"}
      ],
      "Account": [
        {"name": "accountType", "type": "string"},
        {"name": "finId", "type": "string"}
      ],
      "TransactionDetails": [
        {"name": "operationId", "type": "string"},
        {"name": "operationType", "type": "string"},
        {"name": "transactionId", "type": "string"}
      ],
      "Asset": [
        {"name": "assetId", "type": "string"},
        {"name": "assetType", "type": "string"}
      ],
      "TradeDetails": [
        {"name": "executionPlanId", "type": "string"},
        {"name": "instructionSequenceNumber", "type": "string"}
      ],
      "Receipt": [
        {"name": "id", "type": "string"},
        {"name": "source", "type": "Account"},
        {"name": "destination", "type": "Account"},
        {"name": "asset", "type": "Asset"},
        {"name": "tradeDetails", "type": "TradeDetails"},
        {"name": "transactionDetails", "type": "TransactionDetails"}
      ]
    }
  }

Supported FinP2P signatures use ECDSA with the SECP256K1 curve and KECCAK hashing for optimized verification in the EVM. Signatures are encoded according to the EEA specification as defined in section 3.7.1 (Multiple ECDSA Signatures) to hold FinP2P receipt signatures.

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 FinP2P transaction attestation proof can make use of the following structures containing a FinP2P receipt:


  struct EIP712Domain {
    string name;
    string version;
    uint256 chainId;
    address verifyingContract;
  }
  struct Asset {
    string assetId;
    string assetType;
  }
  struct TransactionDetails {
    string operationId;
    string operationType;
    string transactionId;
  }
  struct TradeDetails {
    string executionPlanId;
    uint256 instructionSequenceNumber;
  }
  struct Account {
    string accountType;
    string finId;
  }
  struct Receipt {
    string id;
    Account source;
    Account destination;
    Asset asset;
    TradeDetails tradeDetails;
    TransactionDetails transactionDetails;
  }
  struct TxData {
    bytes inputParameters;
    string command;
    EIP712.EIP712Domain domainParameters;
    Receipt receipt;
  }

Where the EIP712Domain structure contains FinP2P domain parameters.

Properties:

  • name: The user readable name of the signing domain.
  • version: Current major version of the signing domain.
  • chainId: The EIP-155 chain id.
  • verifyingContract: Destination verifying contract address.

Where the Receipt structure contains FinP2P receipt data.

Properties:

  • assetId: Asset identification, e.g. ownera, USD, BTC.
  • assetType: Asset type, e.g. finp2p, fiat, cryptocurrency.
  • operationId: Operation identification on the FinP2P network.
  • operationType: Type of operation performed by the transaction.
  • transactionId: Transaction identification on the underlying DLT network.
  • executionPlanId: Execution plan identification corresponding to a unique trade identifier.
  • instructionSequenceNumber: Unique instruction number for the step of the execution plan that was performed.
  • accountType: Type of FinP2P account, e.g. finp2p
  • finId: FinP2P account identification in the form of a compressed public key.
  • id: Unique receipt identification.
  • source: Source FinP2P account.
  • destination: Destination FinP2P account.
  • asset: Asset used in the trade.
  • tradeDetails: Trade details.
  • transactionDetails: Transaction details.

Where the TxData structure contains the Ethereum function input parameters, FinP2P receipt data and domain parameters required to recreate the hash that was signed.

Properties:

  • inputParameters: Input parameters to be verified as being included in the receipt data.
  • command: The unique command constructed from the receipt contents that is used to make the remote function call.
  • domainParameters: EIP712 domain parameters needed to encode typed data.
  • receipt: The FinP2P receipt.

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

The interface for the crosschain verifier contract on the EVM-based network, that is verifying the FinP2P receipt proof, is outlined in section 3.3 (Crosschain verifier interface).

6.5.2 Crosschain Function Call Layer

For every FinP2P receipt, pertaining to a specific execution plan instruction, that gets added to the interop flows, and EVM function call that can be created from it, a translator needs to be registered in the messaging layer. The translator consists of a mapping between receipt fields 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.

EVM and non-EVM based DLT networks MUST implement the interface in section 4.1.1 (Remote Function Call Interface), or an equivalent thereof, to allow functions to be called remotely with a proof that a previous step in the execution plan was executed successfully.

The FinP2P adapter that generates the proof from the receipt needs to know the target network information, where the receipt will be verified, as well as the target contract address where the remote function call must be executed. This information is included in encodedInfo when invoking inboundCall on an EVM network. It 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.

6.5.3 Crosschain Application Layer

The application layer integration consists of implementing specific functions that can be called remotely, via the crosschain function call layer. The existing use case using FinP2P with Ethereum focussed in on DvP (Delivery vs Payment) where securities reside on the FinP2P network as tokenized assets and tokenized cash resides on an Ethereum network in deposit token contracts. The crosschain messaging protocol is used to facilitate remote crosschain function calls to transfer the asset in the FinP2P network and provide payment for it on Ethereum. The approach makes use of FinP2P escrow services to hold and transfer assets. 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.

7. Considerations

7.1 Interoperation Modes

The ISO Blockchain and Distributed Ledger Technology — Interoperability Framework (ISO/CD TS 23516) identifies three interoperation modes: Data Transfer, Asset Transfer, and Asset Exchange. Data Transfer involves copying information between DLTs, potentially with intermediate processing. Asset Transfer allows for the movement of assets from one DLT to another, often involving locking or burning the original asset and creating a wrapped token on the destination network. Asset Exchange enables atomic swaps of assets between different DLTs, where participants must be present on both networks, and the assets remain on their native chains while changing ownership addresses.

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

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

A. Appendix

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

Abstract

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