-
Notifications
You must be signed in to change notification settings - Fork 834
Add ERC: Cross-Chain Tracking #1362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
cad5e54
699b8f7
f2fae1d
f52e530
3192d58
f940c07
d49eb0f
90843ba
f7d984a
d0bbeb1
71c38a5
afca1fa
bcfd56e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,290 @@ | ||
| --- | ||
| title: Cross-Chain Tracking | ||
| description: This EIP standardizes a simplified set of cross-chain bridge transaction event formats, aiming to provide fundamental traceability standard for cross-chain transactions. | ||
|
Check failure on line 3 in ERCS/erc-8088.md
|
||
| author: Shulei(@baishuo13)<[email protected]>, Jeff Fei (@77eff) <[email protected]>, Kenny Kung (@kennyk10) <[email protected]> | ||
|
Check failure on line 4 in ERCS/erc-8088.md
|
||
| discussions-to: https://ethereum-magicians.org/t/erc-8088-cross-chain-tracking-standard/26677 | ||
| status: Draft | ||
| type: Standards Track | ||
| category: ERC | ||
| created: 2025-11-17 | ||
| requires: EIP-155,EIP-172 | ||
|
Check failure on line 10 in ERCS/erc-8088.md
|
||
| --- | ||
|
|
||
|
|
||
|
|
||
| ## Abstract | ||
|
|
||
| By standardizing cross-chain bridge transaction event, it establishes a basis for regulatory compliance and user verification. This EIP contributes to improved security monitoring, and forensic analysis of cross-chain fund flows. | ||
|
|
||
| ## Motivation | ||
|
|
||
| The cross-chain ecosystem is currently experiencing rapid expansion, driven by a continuous increase in the number of blockchains and cross-chain bridge assets. However, as each bridge implementation typically uses its own proprietary event formats, the transaction tracking mechanism has become increasingly fragmented. This creates opportunities for illicit funds to be laundered through these cross-chain services which poses significant challenges to the cross-chain ecosystem in terms of security and compliance, and incident response capabilities, directly impacting users, project teams, and regulatory bodies. | ||
| The specific problems include: | ||
| - Lack of Standardized Event Logging: The bridge contract on the destination chain may not record transaction events at all, or different bridges use incompatible message structures. | ||
| - Absence of a Universal Identifier: The lack of a unified cross-chain transaction identifier, coupled with differences in event field names and formats, results in the separation of transaction records between the source and destination chains, making them impossible to correlate. | ||
|
|
||
| ## Specification | ||
|
|
||
| The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174). | ||
|
|
||
| ### Standard Event Formats | ||
|
|
||
| ```solidity | ||
| event CrossChainTransactionInitiated( | ||
| bytes32 indexed messageId, // Cross-chain message unique identifier | ||
| address indexed destChainBridge, // Bridge contract address emitting CrossChainTransferCompleted event on destination chain | ||
| uint256 indexed destChainId, // Destination chain ID | ||
| bytes messageBody, | ||
| uint256 nonce | ||
| ); | ||
| ``` | ||
|
|
||
| - The `CrossChainTransactionInitiatedevent` **MUST** be emitted when a cross-chain transaction is initiated on the source chain, generating a cross-chain transaction event. | ||
| - This event is monitored by existing off-chain indexers, as long as the event is supported. This event field can be added on top of existing bridges as an extended event in the source chain or as a standard event field of a bridge event. | ||
| - The `messageBody` field is protocol-specific and allowed to be customized while it **SHOULD** contain necessary cross-chain transaction data to maintain traceability. | ||
| - The `indexed` keyward is used to declare parameters in an event and indicate that the value of that parameter **SHOULD** be indexed. | ||
|
|
||
| ```solidity | ||
| event CrossChainMessageCompleted( | ||
| bytes32 indexed messageId, | ||
| bytes32 indexed messageBodyHash // Used to verify if the messageBody is consistent. | ||
| ) | ||
| ``` | ||
|
|
||
| - The `CrossChainTransferCompleted` event **MUST** be emitted when a cross-chain transaction is successfully completed on the target chain. | ||
| - The definiation of `messageBodyHash` is `messageBodyHash = keccak256(messageBody)`, which is used to verify the integrity of cross-chain message. | ||
|
|
||
| ### Cross-Chain Message ID Generation | ||
|
|
||
| The messageId in cross-chain events is encoded as follow: | ||
| - `messageId = keccak256(sourceChainId || sourceChainBridge || destChainId || destChainBridge || nonce)` | ||
|
|
||
| It **SHALL** be generated using this structure to ensure global uniqueness, preventing replay attack, where: | ||
| - All fields are deterministically encoded | ||
| - The `nonce` is a strictly increasing value per sender or channel on the source chain. | ||
|
|
||
| ```solidity | ||
| function generateCrossChainMessageId( | ||
| uint256 sourceChainId, // Source chain ID | ||
| address sourceChainBridge, // Source chain bridge contract address | ||
| uint256 destChainId, // Destination chain ID | ||
| address destChainBridge, // Destination chain bridge contract address | ||
| uint256 nonce // Message sequence number | ||
| ) public pure returns (bytes32) { | ||
| return keccak256(abi.encodePacked( | ||
| sourceChainId, | ||
| sourceChainBridge, | ||
| destChainId, | ||
| destChainBridge, | ||
| nonce | ||
| )); | ||
| } | ||
| ``` | ||
|
|
||
| ### Implementation Requirements | ||
|
|
||
| - Bridge contracts **MAY** implement these events as an extension to existing backwards compatibility while still achieving cross-chain transaction tracking. | ||
| - The content format of the `messageBody` field is protocol-specific but **SHOULD** contain necessary cross-chain transaction data. | ||
| - The event **MUST** be triggered at the appropriate stage of the transaction lifecycle, and all fields in the event **MUST** be valid. The `CrossChainTransactionInitiated` event **SHOULD** be sent when the message is sent on the original chain, and the ```CrossChainTransferCompleted``` event **SHOULD** be sent when funds are withdrawn from the target chain. | ||
|
|
||
| ## Rationale | ||
|
|
||
| **Minimal Design Approac**:The standard adopts a minimal design philosophy which include only necessary events to avoid over-standardization while providing sufficient tracking capabilities. | ||
| **Implementation Flexibility**:The messageBody field allows individual bridge protocols to include protocol-specific execution data while maintaining event structure consistency. | ||
| - ```messageBody = (messageBodyDomain || sourceTokenSender || destTokenReceiver || sourceTokenAddress || destTokenAddress || amount)``` | ||
| > e.g:messageBodyDomain = "TOKEN_BRIDGE",sourceTokenSender = "Source chain token sender address", destTokenReceiver = "Destination chain token receiver address",sourceTokenAddress = "Source chain token address",destTokenAddress = "Destination chain token address" ,amount = "Transfer amount". | ||
|
|
||
| Cross-chain message ID **SHOULD** be generated using the following method to ensure uniqueness: | ||
| ```solidity | ||
| function generateCrossChainMessageHash( | ||
| address messageBodyDomain, // Type identifier for message body decoding | ||
| address sourceTokenSender, // Source chain token sender address | ||
| address destTokenReceiver, // Destination chain token receiver address | ||
| address sourceTokenAddress, // Source chain token address | ||
| address destTokenAddress // Destination chain token address | ||
| uint256 amount // Transfer amount | ||
| ) public pure returns (bytes32) { | ||
| return keccak256(abi.encodePacked( | ||
| messageBodyDomain, | ||
| sourceTokenSender, | ||
| destTokenReceiver, | ||
| sourceTokenAddress, | ||
| destTokenAddress, | ||
| amount | ||
| )); | ||
| } | ||
| ``` | ||
| **Guarantee Uniqueness**:The messageId generation algorithm combines multiple chain-specific and transaction-specific parameters to ensure sufficient entropy, preventing overlapping with different bridge implementations. | ||
| **Event Indexing**:Indexing of messageId, destChainId, and destChainBridge supports efficient filtering and querying for common use cases, such as tracking specific destination chains or bridge contracts for transaction correlation. | ||
| ## Backwards Compatibility | ||
| This EIP is fully backward compatible as it defines new event interfaces without modifying existing contract functionality. Bridge implementations **MAY** choose to implement these events alongside existing event structures. No breaking changes are introduced to existing smart contracts or protocols. Bridge protocols **MAY** adopt this standard gradually according to specific requirements. | ||
|
|
||
| ## Test cases | ||
|
Check failure on line 122 in ERCS/erc-8088.md
|
||
| Example for tracking bridge event with this EIP standard: | ||
| 1. Simulate the processing of cross-chain transactions | ||
| 2. Monitor the source chain event (```CrossChainTransactionInitiated```) of cross-chain transactions to get ```messageId``` and ```messageBodyHash``` | ||
| 3. Query the target chain event (```CrossChainMessageCompleted```) of the bridge contract to associate it with the cross-chain transaction, and verify it by cross-checking ```messageId``` and ```messageBodyHash```. Once the verification is successful, it can be associated with the target chain monitoring object through the ```destChainId``` + ```destBridgeAddress``` fields in the source event | ||
|
|
||
|  | ||
| **<center><font size=2>Figure 1: Simulation of source chain and target chain event generation</font></center>** | ||
|  | ||
| **<center><font size=2>Figure 2:Cross-chain message verification</font></center>** | ||
| ## Reference Implementation | ||
|
|
||
| ```solidity | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| /** | ||
| * @title CrossChainTrackingStandard | ||
| * @dev Implementation of EIP-XXXX Cross-Chain Transaction Tracking Standard | ||
| * Provides standardized event tracking for cross-chain transaction lifecycle | ||
| * This contract serves as a base implementation for cross-chain bridge protocols | ||
| * to ensure consistent transaction tracking across different blockchain networks | ||
| */ | ||
| contract CrossChainTrackingStandard { | ||
| /// @dev Transaction sequence counter to ensure unique nonce for each transaction | ||
| /// @notice This counter increments with each initiated transaction to prevent replay attacks | ||
| uint256 public nonce; | ||
| // Mapping to track processed messages to prevent replay attacks | ||
| mapping(bytes32 => bool) private _processedMessages; | ||
|
|
||
| /** | ||
| * @dev Emitted when a cross-chain transaction is initiated on the source chain | ||
| * @param messageId Cross-chain message unique identifier | ||
| * @param destChainBridge Bridge contract address on destination chain | ||
| * @param destChainId Destination chain ID | ||
| * @param messageBody Cross-chain message body containing transaction data | ||
| * @param nonce Cross-chain message sequence number | ||
| */ | ||
| event CrossChainTransactionInitiated( | ||
| bytes32 indexed messageId, | ||
| address indexed destChainBridge, | ||
| uint256 indexed destChainId, | ||
| bytes messageBody, | ||
| uint256 nonce | ||
| ); | ||
|
|
||
| /** | ||
| * @dev Emitted when a cross-chain transaction is successfully completed on the target chain | ||
| * @param messageId Cross-chain message unique identifier | ||
| * @param messageBodyHash Hash of the message body for verification | ||
| */ | ||
| event CrossChainMessageCompleted( | ||
| bytes32 indexed messageId, | ||
| bytes32 indexed messageBodyHash | ||
| ); | ||
|
|
||
| /** | ||
| * @dev Generates a unique cross-chain message ID | ||
| * @param sourceChainId Source chain ID | ||
| * @param sourceChainBridge Bridge contract address on source chain | ||
| * @param destChainId Destination chain ID | ||
| * @param destChainBridge Destination chain bridge contract address | ||
| * @param _nonce Transaction sequence number | ||
| * @return messageId Unique cross-chain message identifier | ||
| */ | ||
| function generateCrossChainTxId( | ||
| uint256 sourceChainId, | ||
| address sourceChainBridge, | ||
| uint256 destChainId, | ||
| address destChainBridge, | ||
| uint256 _nonce | ||
| ) public pure returns (bytes32) { | ||
| return keccak256(abi.encodePacked( | ||
| sourceChainId, | ||
| sourceChainBridge, | ||
| destChainId, | ||
| destChainBridge, | ||
| _nonce | ||
| )); | ||
| } | ||
| /** | ||
| * @dev Generates hash for cross-chain message body | ||
| * @param messageBodyDomain Type identifier for message body decoding | ||
| * @param sourceTokenSender Source chain token sender address | ||
| * @param destTokenReceiver Destination chain token receiver address | ||
| * @param sourceTokenAddress Source chain token address | ||
| * @param destTokenAddress Destination chain token address | ||
| * @param amount Transfer amount | ||
| * @return messageBodyHash Hash of the message body | ||
| */ | ||
| function generateCrossChainMessageHash( | ||
| bytes32 messageBodyDomain, | ||
| address sourceTokenSender, | ||
| address destTokenReceiver, | ||
| address sourceTokenAddress, | ||
| address destTokenAddress, | ||
| uint256 amount | ||
| ) public pure returns (bytes32) { | ||
| return keccak256(abi.encodePacked( | ||
| messageBodyDomain, | ||
| sourceTokenSender, | ||
| destTokenReceiver, | ||
| sourceTokenAddress, | ||
| destTokenAddress, | ||
| amount | ||
| )); | ||
| } | ||
| /** | ||
| * @dev Initiates a cross-chain transaction and emits the standard event | ||
| * @notice messageBody MUST include messageBodyDomain as the first field for type identification | ||
| * @param destChainBridge Bridge contract address on destination chain | ||
| * @param destChainId Destination chain ID | ||
| * @param messageBody Encoded message body with messageBodyDomain as type identifier | ||
| * @return messageId Generated message ID for this transaction | ||
| */ | ||
| function initiateCrossChainTransfer( | ||
| address destChainBridge, | ||
| uint256 destChainId, | ||
| bytes memory messageBody | ||
| ) external returns (bytes32) { | ||
| uint256 _currentNonce = ++nonce; | ||
| bytes32 messageId = generateCrossChainTxId( | ||
| block.chainid, // Current chain ID as source chain ID (EIP-155) | ||
| address(this), // Source chain bridge contract address (current contract) | ||
| destChainId, | ||
| destChainBridge, | ||
| _currentNonce | ||
| ); | ||
| emit CrossChainTransactionInitiated( | ||
| messageId, | ||
| destChainBridge, | ||
| destChainId, | ||
| messageBody, | ||
| _currentNonce | ||
| ); | ||
| return messageId; | ||
| } | ||
|
|
||
| /** | ||
| * @dev Completes a cross-chain transaction and emits the completion event | ||
| * @notice Implementations SHOULD decode messageBody based on messageBodyDomain type | ||
| * @param messageId Cross-chain message unique identifier | ||
| * @param messageBody Cross-chain message body | ||
| * @return success Whether the completion was successful | ||
| */ | ||
| function completeCrossChainMessage( | ||
| bytes32 messageId, | ||
| bytes memory messageBody | ||
| ) external returns (bool) { | ||
| // NOTE: Require additional signature verification | ||
| require(!_processedMessages[messageId], "Message already processed"); | ||
|
|
||
| _processedMessages[messageId] = true; | ||
| bytes32 messageBodyHash = keccak256(messageBody); | ||
|
|
||
| emit CrossChainMessageCompleted(messageId, messageBodyHash); | ||
|
|
||
| return true; | ||
| } | ||
| } | ||
| ``` | ||
| ## Security Considerations | ||
| - **Transaction ID Collision Resistance**:Implementations MUST ensure transaction ID generation has sufficient entropy to prevent collision attacks. The recommended keccak256 algorithm provides adequate collision resistance for typical cross-chain bridge usage, reducing the likelihood of enumeration and guessing attacks. | ||
| - **Prevention of Attack Forgery**: The source chain event includes an additional ```destChainBridge``` field to correlate the response status of cross-chain transactions with the target chain address. Since transactions that fail cross-chain validation will revert directly, and the target chain only records events from successfully validated transactions, even if an attacker attempts to confuse monitoring by forging a large number of identical cross-chain transactions simultaneously, it will not ultimately affect the correlation between source and target chain transactions. | ||
| - **Bridge-Specific Security**:This standard only defines event interfaces. Individual bridge implementations remain responsible for their protocol-specific security considerations, including but not limited to multi-signature validator sets, transaction data validation, economic security, cryptographic proofs, and ensuring bridge protocols undergo security audits. | ||
| - **Event Data Verification**:Bridge protocols SHOULD implement appropriate verification mechanisms to ensure the authenticity and integrity of event data. Event emission does not guarantee transaction success; protocols MUST verify on-chain state changes. | ||
|
|
||
| ## Copyright | ||
|
|
||
| Copyright and related rights waived via [CC0](../LICENSE.md). | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assigning next sequential EIP/ERC/RIP number.
Numbers are assigned by editors & associates.
Please also update the filename.