Documentation Index
Fetch the complete documentation index at: https://eco.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
The Metalayer Prover enables cross-chain intent verification using Caldera Metalayer’s messaging infrastructure. It receives messages via IMetalayerRecipient and extends MessageBridgeProver for common proving functionality.
Architecture
Destination Chain Source Chain
━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━
Portal Portal
↓ ↑
MetaProver MetaProver
↓ ↑
Metalayer Router ──────────→ Metalayer Router
Configuration
constructor(
address router, // Metalayer router on this chain
address portal, // Portal contract address
bytes32[] memory provers, // Trusted prover addresses on other chains
uint256 minGasLimit // Minimum gas limit (defaults to 200k if zero)
)
Key Points:
router: Chain-specific Metalayer router address
portal: Portal contract that initiates proving
provers: Whitelist of trusted provers on source chains (bytes32 format for cross-VM compatibility)
minGasLimit: Enforced minimum is 200,000 gas if zero or lower value provided
Proving Flow
Sending Proofs (Destination → Source)
Called by Portal after intent fulfillment:
portal.prove{value: fee}(
address(prover),
sourceChainDomainID,
intentHashes,
data
);
Data Parameter:
abi.encode(
MetaProver.UnpackedData({
sourceChainProver: bytes32(uint256(uint160(sourceProverAddress))),
gasLimit: 250000 // Minimum MIN_GAS_LIMIT enforced
})
)
Receiving Proofs (Source Chain)
Metalayer router calls handle() with message containing:
- 8 bytes: destination chain ID
- 64 bytes per intent:
[intentHash (32 bytes)][claimant (32 bytes)]
function handle(
uint32 origin,
bytes32 sender,
bytes calldata message,
ReadOperation[] calldata operations,
bytes[] calldata operationsData
) external payable
Only whitelisted senders accepted via isWhitelisted(sender).
Fee Calculation
function fetchFee(
uint64 domainID,
bytes calldata encodedProofs,
bytes calldata data
) public view returns (uint256)
Uses custom hook metadata with actual gas limit for accurate estimation:
bytes memory metadata = StandardHookMetadata.formatMetadata(
ETH_QUOTE_VALUE, // 1e36 (high value to avoid quote failures)
unpacked.gasLimit, // Actual gas limit from data
msg.sender, // Refund address
bytes("") // Custom metadata
);
Always call before proving to get accurate fees.
Domain IDs
Critical: Metalayer uses custom domain IDs, not chain IDs.
domain = uint32(domainID);
The sourceChainDomainID parameter must be Metalayer’s domain ID. Consult Caldera Metalayer documentation for mappings.
Finality State
Messages are dispatched with FinalityState.INSTANT:
ROUTER.dispatch{value: fee}(
sourceChainDomain,
recipient,
new ReadOperation[](0), // Empty read operations
message,
FinalityState.INSTANT, // Instant finality
unpacked.gasLimit
);
This provides fast message delivery without waiting for blockchain finality.
Gas Limits
Minimum gas enforced during unpacking:
if (unpacked.gasLimit < MIN_GAS_LIMIT) {
unpacked.gasLimit = MIN_GAS_LIMIT;
}
Default MIN_GAS_LIMIT is 200,000 gas.
Security
Whitelisting
Only provers in the whitelist can send messages:
function isWhitelisted(bytes32 sender) internal view returns (bool)
Access Control
- Only Metalayer router can call
handle()
- Only Portal can call
prove()
- Zero domain ID rejected:
if (origin == 0) revert ZeroDomainID()
Validation
Sender validation in handle():
if (sender == bytes32(0)) revert SenderCannotBeZeroAddress();
Integration Example
// Deploy prover
bytes32[] memory trustedProvers = new bytes32[](1);
trustedProvers[0] = bytes32(uint256(uint160(ethereumProverAddress)));
MetaProver prover = new MetaProver(
metalayerRouter, // Chain-specific router
portalAddress,
trustedProvers,
250_000 // 250k gas minimum
);
// Fulfill and prove
bytes memory proverData = abi.encode(
MetaProver.UnpackedData({
sourceChainProver: bytes32(uint256(uint160(ethereumProver))),
gasLimit: 250_000
})
);
uint256 fee = prover.fetchFee(domainID, encodedProofs, proverData);
portal.fulfillAndProve{value: route.nativeAmount + fee}(
intentHash,
route,
rewardHash,
claimant,
address(prover),
domainID, // Metalayer domain ID
proverData
);
Advantages
- Lowest Costs: Generally cheapest among message bridge provers
- Instant Finality: Fast message delivery with
FinalityState.INSTANT
- Simple Configuration: No delegate setup, straightforward deployment
- Caldera Optimized: Native integration with Caldera rollups
Limitations
- Smallest Chain Coverage: Limited to Caldera-supported chains
- Less Mature: Newer infrastructure compared to Hyperlane/LayerZero
- Limited Tooling: Fewer third-party integrations and explorers
- Caldera Dependency: Primarily designed for Caldera rollup ecosystem
Errors
RouterCannotBeZeroAddress(): Invalid router in constructor
ZeroDomainID(): Origin domain is zero in handle()
SenderCannotBeZeroAddress(): Zero sender in handle()
DomainIdTooLarge(uint64): Domain ID exceeds uint32.max
NonPortalCaller(address): Unauthorized prove() caller
NotWhitelisted(bytes32): Sender not in whitelist
Constants
string public constant PROOF_TYPE = "Meta";
Identifies this prover’s mechanism type.
uint256 private immutable ETH_QUOTE_VALUE = 1e36;
High value used in fee calculation metadata to avoid quote failures in Metalayer router.