Skip to main content
Eco Routes Protocol supports multiple bridge providers for proving intent fulfillment across chains. Each prover implementation enables secure cross-chain message passing to verify that intents have been fulfilled on destination chains.

Available Bridge Provers

The protocol implements five distinct bridge integrations:

Hyperlane

HyperProver - Cross-chain messaging via Hyperlane mailbox

LayerZero

LayerZeroProver - V2 endpoint integration for cross-chain proofs

Chainlink CCIP

CCIPProver - Decentralized oracle network for reliable cross-chain proving

Metalayer

MetaProver - Caldera Metalayer router-based proving

Polymer

PolymerProver - Event-based proving with CrossL2ProverV2

Architecture Overview

All message-based provers (Hyperlane, LayerZero, CCIP, Metalayer) extend from a common base:
BaseProver
  └── MessageBridgeProver
        ├── HyperProver
        ├── LayerZeroProver
        ├── CCIPProver
        └── MetaProver
PolymerProver uses a different architecture based on event proving:
BaseProver
  └── PolymerProver

Common Base Functionality

All provers inherit from BaseProver.sol which provides:
  • Proof Storage: Mapping from intent hash to proof data (claimant + destination)
  • Challenge Mechanism: Anyone can invalidate proofs with mismatched destination chain IDs
  • Portal Integration: Immutable reference to the Portal contract
contracts/prover/BaseProver.sol
mapping(bytes32 => ProofData) internal _provenIntents;

struct ProofData {
    address claimant;
    uint64 destination;
}

Domain IDs vs Chain IDs

Critical: Domain IDs are NOT the same as chain IDs. Each bridge provider uses their own domain ID mapping system.
When calling prover functions, you must use the bridge-specific domain ID:
  • Hyperlane: Custom domain IDs (e.g., Ethereum = 1, Polygon = 137, but check Hyperlane docs)
  • LayerZero: Endpoint IDs (EIDs) that differ from chain IDs
  • Chainlink CCIP: Chain selectors (unique 64-bit identifiers per chain)
  • Metalayer: Metalayer-specific domain IDs
  • Polymer: Uses actual chain IDs
From Inbox.sol:144-151:
contracts/Inbox.sol
/**
 * @dev WARNING: sourceChainDomainID is NOT necessarily the same as chain ID.
 *      Each bridge provider uses their own domain ID mapping system:
 *      - Hyperlane: Uses custom domain IDs that may differ from chain IDs
 *      - LayerZero: Uses endpoint IDs that map to chains differently
 *      - Metalayer: Uses domain IDs specific to their routing system
 *      - Polymer: Uses chainIDs
 */

Common Prove Function

All message-based provers implement this signature from MessageBridgeProver.sol:112-117:
contracts/prover/MessageBridgeProver.sol
function prove(
    address sender,
    uint64 domainID,
    bytes calldata encodedProofs,
    bytes calldata data
) external payable;

Parameters

sender
address
Address that initiated the proving request (receives refunds)
domainID
uint64
Bridge-specific domain ID of the source chain (where intent was created)
encodedProofs
bytes
Encoded (intentHash, claimant) pairs. Format: 8-byte chain ID + (32-byte hash + 32-byte claimant) pairs
data
bytes
Bridge-specific encoded data for message formatting. Structure varies by prover implementation.

Fee Calculation

All provers implement fetchFee() to calculate cross-chain messaging costs:
function fetchFee(
    uint64 domainID,
    bytes calldata encodedProofs,
    bytes calldata data
) public view returns (uint256);
The prove() function automatically:
  1. Calculates required fee via fetchFee()
  2. Validates msg.value >= fee
  3. Refunds excess payment to sender

Message Flow

  1. Destination Chain: Intent is fulfilled via Inbox.fulfillAndProve()
  2. Proof Encoding: Intent hash and claimant are encoded with chain ID prefix
  3. Bridge Dispatch: Prover sends message to source chain via bridge
  4. Source Chain: Prover receives message and stores proof
  5. Reward Claim: Portal validates proof and distributes rewards

Security Features

Whitelist Protection

All message-based provers use whitelisting to prevent unauthorized proof submissions:
contracts/prover/MessageBridgeProver.sol
if (!isWhitelisted(messageSender)) {
    revert UnauthorizedIncomingProof(messageSender);
}

Proof Challenge

Anyone can challenge invalid proofs (from BaseProver.sol:112-129):
contracts/prover/BaseProver.sol
function challengeIntentProof(
    uint64 destination,
    bytes32 routeHash,
    bytes32 rewardHash
) external {
    bytes32 intentHash = keccak256(
        abi.encodePacked(destination, routeHash, rewardHash)
    );
    
    ProofData memory proof = _provenIntents[intentHash];
    
    if (proof.claimant != address(0) && proof.destination != destination) {
        delete _provenIntents[intentHash];
        emit IntentProofInvalidated(intentHash);
    }
}

Next Steps

Explore the specific integration guides for each bridge provider:

Build docs developers (and LLMs) love