Initial commit
This commit is contained in:
138
contracts/oracle/OracleWithCCIP.sol
Normal file
138
contracts/oracle/OracleWithCCIP.sol
Normal file
@@ -0,0 +1,138 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
import "./Aggregator.sol";
|
||||
import "../ccip/CCIPSender.sol";
|
||||
|
||||
/**
|
||||
* @title Oracle Aggregator with CCIP Integration
|
||||
* @notice Extends Aggregator with CCIP cross-chain messaging capabilities
|
||||
* @dev Automatically sends oracle updates to other chains via CCIP when updates occur
|
||||
*/
|
||||
contract OracleWithCCIP is Aggregator {
|
||||
CCIPSender public ccipSender;
|
||||
bool public ccipEnabled;
|
||||
|
||||
// Destination chain configurations (using CCIPSender's destinations)
|
||||
uint64[] public ccipDestinationChains;
|
||||
|
||||
event CCIPUpdateSent(
|
||||
bytes32 indexed messageId,
|
||||
uint64 indexed destinationChainSelector,
|
||||
uint256 answer,
|
||||
uint256 roundId
|
||||
);
|
||||
event CCIPEnabled(bool enabled);
|
||||
event CCIPSenderUpdated(address oldSender, address newSender);
|
||||
|
||||
constructor(
|
||||
string memory _description,
|
||||
address _admin,
|
||||
uint256 _heartbeat,
|
||||
uint256 _deviationThreshold,
|
||||
address _ccipSender
|
||||
) Aggregator(_description, _admin, _heartbeat, _deviationThreshold) {
|
||||
require(_ccipSender != address(0), "OracleWithCCIP: zero sender address");
|
||||
ccipSender = CCIPSender(_ccipSender);
|
||||
ccipEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Update the answer and send to CCIP destinations
|
||||
* @param answer New answer value
|
||||
*/
|
||||
function updateAnswer(uint256 answer) external override onlyTransmitter whenNotPaused {
|
||||
uint256 currentRound = latestRound;
|
||||
Round storage round = rounds[currentRound];
|
||||
|
||||
// Check if we need to start a new round
|
||||
if (round.updatedAt == 0 ||
|
||||
block.timestamp >= round.startedAt + heartbeat ||
|
||||
shouldUpdate(answer, round.answer)) {
|
||||
currentRound = latestRound + 1;
|
||||
latestRound = currentRound;
|
||||
|
||||
rounds[currentRound] = Round({
|
||||
answer: answer,
|
||||
startedAt: block.timestamp,
|
||||
updatedAt: block.timestamp,
|
||||
answeredInRound: currentRound,
|
||||
transmitter: msg.sender
|
||||
});
|
||||
|
||||
emit NewRound(currentRound, msg.sender, block.timestamp);
|
||||
|
||||
// Send to CCIP destinations if enabled
|
||||
if (ccipEnabled) {
|
||||
_sendToCCIP(currentRound, answer);
|
||||
}
|
||||
} else {
|
||||
// Update existing round
|
||||
round.updatedAt = block.timestamp;
|
||||
round.transmitter = msg.sender;
|
||||
}
|
||||
|
||||
emit AnswerUpdated(int256(answer), currentRound, block.timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Send oracle update to all CCIP destinations
|
||||
*/
|
||||
function _sendToCCIP(uint256 roundId, uint256 answer) internal {
|
||||
uint64[] memory destinations = ccipSender.getDestinationChains();
|
||||
|
||||
for (uint256 i = 0; i < destinations.length; i++) {
|
||||
uint64 chainSelector = destinations[i];
|
||||
|
||||
try ccipSender.sendOracleUpdate(
|
||||
chainSelector,
|
||||
answer,
|
||||
roundId,
|
||||
block.timestamp
|
||||
) returns (bytes32 messageId) {
|
||||
emit CCIPUpdateSent(messageId, chainSelector, answer, roundId);
|
||||
} catch {
|
||||
// Log error but don't revert
|
||||
// In production, consider adding error tracking
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Enable/disable CCIP
|
||||
*/
|
||||
function setCCIPEnabled(bool enabled) external {
|
||||
require(msg.sender == admin, "OracleWithCCIP: only admin");
|
||||
ccipEnabled = enabled;
|
||||
emit CCIPEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Update CCIP sender
|
||||
*/
|
||||
function updateCCIPSender(address newSender) external {
|
||||
require(msg.sender == admin, "OracleWithCCIP: only admin");
|
||||
require(newSender != address(0), "OracleWithCCIP: zero address");
|
||||
|
||||
address oldSender = address(ccipSender);
|
||||
ccipSender = CCIPSender(newSender);
|
||||
|
||||
emit CCIPSenderUpdated(oldSender, newSender);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get CCIP destinations
|
||||
*/
|
||||
function getCCIPDestinations() external view returns (uint64[] memory) {
|
||||
return ccipSender.getDestinationChains();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get fee for sending to CCIP destination
|
||||
*/
|
||||
function getCCIPFee(uint64 chainSelector) external view returns (uint256) {
|
||||
bytes memory data = abi.encode(uint256(0), uint256(0), uint256(0));
|
||||
return ccipSender.calculateFee(chainSelector, data);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user