- 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.
92 lines
2.6 KiB
Solidity
92 lines
2.6 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "./IRouterClient.sol";
|
|
|
|
/**
|
|
* @title CCIP Message Validator
|
|
* @notice Validates CCIP messages for replay protection and format
|
|
* @dev Provides message validation utilities
|
|
*/
|
|
library CCIPMessageValidator {
|
|
// Message nonce tracking per source chain
|
|
struct MessageNonce {
|
|
uint256 nonce;
|
|
bool used;
|
|
}
|
|
|
|
/**
|
|
* @notice Validate message format
|
|
* @param message The CCIP message to validate
|
|
* @return valid True if message format is valid
|
|
*/
|
|
function validateMessageFormat(
|
|
IRouterClient.Any2EVMMessage memory message
|
|
) internal pure returns (bool valid) {
|
|
// Check message ID is not zero
|
|
if (message.messageId == bytes32(0)) {
|
|
return false;
|
|
}
|
|
|
|
// Check source chain selector is valid
|
|
if (message.sourceChainSelector == 0) {
|
|
return false;
|
|
}
|
|
|
|
// Check sender is not empty
|
|
if (message.sender.length == 0) {
|
|
return false;
|
|
}
|
|
|
|
// Check data is not empty
|
|
if (message.data.length == 0) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @notice Validate oracle data format
|
|
* @param data The encoded oracle data
|
|
* @return valid True if data format is valid
|
|
* @return answer Decoded answer
|
|
* @return roundId Decoded round ID
|
|
* @return timestamp Decoded timestamp
|
|
*/
|
|
function validateOracleData(
|
|
bytes memory data
|
|
) internal view returns (
|
|
bool valid,
|
|
uint256 answer,
|
|
uint256 roundId,
|
|
uint256 timestamp
|
|
) {
|
|
// Check minimum data length (3 uint256 = 96 bytes)
|
|
if (data.length < 96) {
|
|
return (false, 0, 0, 0);
|
|
}
|
|
|
|
// Decode oracle data directly (no need for try-catch in library)
|
|
(uint256 _answer, uint256 _roundId, uint256 _timestamp) = abi.decode(data, (uint256, uint256, uint256));
|
|
|
|
// Validate answer is not zero
|
|
if (_answer == 0) {
|
|
return (false, 0, 0, 0);
|
|
}
|
|
|
|
// Validate timestamp is reasonable (not too far in future/past)
|
|
// Note: Using uint256 to avoid underflow
|
|
uint256 currentTime = block.timestamp;
|
|
if (_timestamp > currentTime + 300) {
|
|
return (false, 0, 0, 0);
|
|
}
|
|
if (currentTime > _timestamp && currentTime - _timestamp > 3600) {
|
|
return (false, 0, 0, 0);
|
|
}
|
|
|
|
return (true, _answer, _roundId, _timestamp);
|
|
}
|
|
}
|
|
|