# CCIP Message Format ## Overview This document describes the message format used for CCIP cross-chain oracle updates. ## Message Structure CCIP messages contain encoded oracle data in the following format: ```solidity struct OracleMessage { uint256 answer; // Oracle price/answer (scaled by 10^8) uint256 roundId; // Round ID for this update uint256 timestamp; // Unix timestamp of the update } ``` ## Encoding Messages are encoded using ABI encoding: ```solidity bytes memory messageData = abi.encode(answer, roundId, timestamp); ``` ## Decoding On the receiving chain, messages are decoded: ```solidity (uint256 answer, uint256 roundId, uint256 timestamp) = abi.decode(message.data, (uint256, uint256, uint256)); ``` ## Example ### Sending Message ```solidity uint256 price = 25000000000; // $250.00 (scaled by 10^8) uint256 roundId = 12345; uint256 timestamp = block.timestamp; bytes memory messageData = abi.encode(price, roundId, timestamp); CCIPSender sender = CCIPSender(senderAddress); uint256 fee = sender.calculateFee(targetChainSelector, messageData); sender.sendOracleUpdate{value: fee}(targetChainSelector, receiverAddress, messageData); ``` ### Receiving Message ```solidity function ccipReceive( IRouterClient.Any2EVMMessage calldata message ) external onlyRouter { (uint256 answer, uint256 roundId, uint256 timestamp) = abi.decode( message.data, (uint256, uint256, uint256) ); // Update oracle updateOracle(answer, roundId, timestamp); } ``` ## Data Types ### Answer (uint256) - Oracle price/value - Scaled by 10^8 (8 decimal places) - Example: $250.00 = 25000000000 ### Round ID (uint256) - Sequential round identifier - Increments with each update - Used for ordering and deduplication ### Timestamp (uint256) - Unix timestamp (seconds since epoch) - When the price was observed - Used for staleness checks ## Message Size Typical message size: ~96 bytes (3 * 32 bytes) Maximum recommended size: 256 bytes ## Validation Before processing, validate: 1. **Message ID**: Check for replay attacks 2. **Source Chain**: Verify source chain selector 3. **Sender**: Verify sender address is authorized 4. **Timestamp**: Check timestamp is recent 5. **Round ID**: Ensure round ID is sequential ## Error Handling ### Invalid Format If message cannot be decoded: ```solidity try abi.decode(message.data, (uint256, uint256, uint256)) returns (uint256, uint256, uint256) { // Process message } catch { // Log error and reject message emit InvalidMessageFormat(message.messageId); return; } ``` ### Stale Data Check timestamp is recent: ```solidity require(block.timestamp - timestamp < MAX_STALENESS, "Data too stale"); ``` ### Invalid Round ID Ensure round ID is sequential: ```solidity require(roundId > lastRoundId, "Invalid round ID"); ``` ## Security Considerations 1. **Replay Protection**: Track processed message IDs 2. **Source Validation**: Verify source chain and sender 3. **Data Validation**: Validate all fields before processing 4. **Access Control**: Only authorized contracts can receive messages ## References - [CCIP Integration Guide](docs/CCIP_INTEGRATION.md) - [CCIP Router Setup](docs/CCIP_ROUTER_SETUP.md) - [Chainlink CCIP Documentation](https://docs.chain.link/ccip)