- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
148 lines
3.2 KiB
Markdown
148 lines
3.2 KiB
Markdown
# 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)
|
|
|