- 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.
186 lines
5.6 KiB
Solidity
186 lines
5.6 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
/**
|
|
* @title MainnetTether
|
|
* @notice Anchors Chain-138 state proofs to Ethereum Mainnet (Kaleido-style)
|
|
* @dev Stores signed state proofs from Chain-138 validators, creating an immutable
|
|
* and verifiable record of Chain-138's state on Mainnet
|
|
*/
|
|
contract MainnetTether {
|
|
address public admin;
|
|
bool public paused;
|
|
|
|
// Chain-138 chain ID
|
|
uint64 public constant CHAIN_138 = 138;
|
|
|
|
// State proof structure
|
|
struct StateProof {
|
|
uint256 blockNumber; // Chain-138 block number
|
|
bytes32 blockHash; // Chain-138 block hash
|
|
bytes32 stateRoot; // Chain-138 state root
|
|
bytes32 previousBlockHash; // Previous block hash
|
|
uint256 timestamp; // Block timestamp
|
|
bytes signatures; // Collective signatures from validators
|
|
uint256 validatorCount; // Number of validators that signed
|
|
bytes32 proofHash; // Hash of the proof (for indexing)
|
|
}
|
|
|
|
// Mapping: blockNumber => StateProof
|
|
mapping(uint256 => StateProof) public stateProofs;
|
|
|
|
// Array of all anchored block numbers (for iteration)
|
|
uint256[] public anchoredBlocks;
|
|
|
|
// Mapping: proofHash => bool (replay protection)
|
|
mapping(bytes32 => bool) public processed;
|
|
|
|
// Events
|
|
event AdminChanged(address indexed newAdmin);
|
|
event Paused();
|
|
event Unpaused();
|
|
event StateProofAnchored(
|
|
uint256 indexed blockNumber,
|
|
bytes32 indexed blockHash,
|
|
bytes32 indexed stateRoot,
|
|
uint256 timestamp,
|
|
uint256 validatorCount
|
|
);
|
|
|
|
modifier onlyAdmin() {
|
|
require(msg.sender == admin, "only admin");
|
|
_;
|
|
}
|
|
|
|
modifier whenNotPaused() {
|
|
require(!paused, "paused");
|
|
_;
|
|
}
|
|
|
|
constructor(address _admin) {
|
|
require(_admin != address(0), "zero admin");
|
|
admin = _admin;
|
|
}
|
|
|
|
/**
|
|
* @notice Anchor a state proof from Chain-138
|
|
* @param blockNumber Chain-138 block number
|
|
* @param blockHash Chain-138 block hash
|
|
* @param stateRoot Chain-138 state root
|
|
* @param previousBlockHash Previous block hash
|
|
* @param timestamp Block timestamp
|
|
* @param signatures Collective signatures from validators
|
|
* @param validatorCount Number of validators that signed
|
|
*/
|
|
function anchorStateProof(
|
|
uint256 blockNumber,
|
|
bytes32 blockHash,
|
|
bytes32 stateRoot,
|
|
bytes32 previousBlockHash,
|
|
uint256 timestamp,
|
|
bytes calldata signatures,
|
|
uint256 validatorCount
|
|
) external onlyAdmin whenNotPaused {
|
|
require(blockNumber > 0, "invalid block");
|
|
require(blockHash != bytes32(0), "invalid hash");
|
|
require(stateRoot != bytes32(0), "invalid state root");
|
|
require(validatorCount > 0, "no validators");
|
|
require(signatures.length > 0, "no signatures");
|
|
|
|
// Calculate proof hash for replay protection
|
|
bytes32 proofHash = keccak256(
|
|
abi.encodePacked(
|
|
blockNumber,
|
|
blockHash,
|
|
stateRoot,
|
|
previousBlockHash,
|
|
timestamp,
|
|
signatures
|
|
)
|
|
);
|
|
|
|
require(!processed[proofHash], "already processed");
|
|
require(stateProofs[blockNumber].blockNumber == 0, "block already anchored");
|
|
|
|
// Store state proof
|
|
stateProofs[blockNumber] = StateProof({
|
|
blockNumber: blockNumber,
|
|
blockHash: blockHash,
|
|
stateRoot: stateRoot,
|
|
previousBlockHash: previousBlockHash,
|
|
timestamp: timestamp,
|
|
signatures: signatures,
|
|
validatorCount: validatorCount,
|
|
proofHash: proofHash
|
|
});
|
|
|
|
anchoredBlocks.push(blockNumber);
|
|
processed[proofHash] = true;
|
|
|
|
emit StateProofAnchored(
|
|
blockNumber,
|
|
blockHash,
|
|
stateRoot,
|
|
timestamp,
|
|
validatorCount
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @notice Get state proof for a specific block
|
|
* @param blockNumber Chain-138 block number
|
|
* @return proof State proof structure
|
|
*/
|
|
function getStateProof(uint256 blockNumber) external view returns (StateProof memory proof) {
|
|
require(stateProofs[blockNumber].blockNumber != 0, "not anchored");
|
|
return stateProofs[blockNumber];
|
|
}
|
|
|
|
/**
|
|
* @notice Check if a block is anchored
|
|
* @param blockNumber Chain-138 block number
|
|
* @return true if anchored
|
|
*/
|
|
function isAnchored(uint256 blockNumber) external view returns (bool) {
|
|
return stateProofs[blockNumber].blockNumber != 0;
|
|
}
|
|
|
|
/**
|
|
* @notice Get total number of anchored blocks
|
|
* @return count Number of anchored blocks
|
|
*/
|
|
function getAnchoredBlockCount() external view returns (uint256) {
|
|
return anchoredBlocks.length;
|
|
}
|
|
|
|
/**
|
|
* @notice Get anchored block number at index
|
|
* @param index Index in anchoredBlocks array
|
|
* @return blockNumber Block number
|
|
*/
|
|
function getAnchoredBlock(uint256 index) external view returns (uint256) {
|
|
require(index < anchoredBlocks.length, "out of bounds");
|
|
return anchoredBlocks[index];
|
|
}
|
|
|
|
/**
|
|
* @notice Admin functions
|
|
*/
|
|
function setAdmin(address newAdmin) external onlyAdmin {
|
|
require(newAdmin != address(0), "zero admin");
|
|
admin = newAdmin;
|
|
emit AdminChanged(newAdmin);
|
|
}
|
|
|
|
function pause() external onlyAdmin {
|
|
paused = true;
|
|
emit Paused();
|
|
}
|
|
|
|
function unpause() external onlyAdmin {
|
|
paused = false;
|
|
emit Unpaused();
|
|
}
|
|
}
|
|
|